/* Android IMSI-Catcher Detector | (c) AIMSICD Privacy Project
* -----------------------------------------------------------
* LICENSE: http://git.io/vki47 | TERMS: http://git.io/vki4o
* -----------------------------------------------------------
*/
package com.secupwn.aimsicd;
import android.app.Activity;
import android.content.Intent;
import android.os.Vibrator;
import android.support.v4.content.LocalBroadcastManager;
import android.util.SparseArray;
import com.secupwn.aimsicd.constants.TinyDbKeys;
import com.secupwn.aimsicd.data.DefaultDataTransaction;
import com.secupwn.aimsicd.enums.Status;
import com.secupwn.aimsicd.utils.BaseAsyncTask;
import com.secupwn.aimsicd.utils.TinyDB;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import io.freefair.android.injection.annotation.Inject;
import io.freefair.android.injection.app.InjectionAppCompatActivity;
import io.freefair.android.injection.app.InjectionApplication;
import io.freefair.android.injection.modules.AndroidLoggerModule;
import io.freefair.android.injection.modules.OkHttpModule;
import io.freefair.android.util.logging.Logger;
import io.realm.Realm;
import io.realm.RealmConfiguration;
public class AndroidIMSICatcherDetector extends InjectionApplication {
private static WeakReference<AndroidIMSICatcherDetector> instance;
public static AndroidIMSICatcherDetector getInstance() {
return instance.get();
}
private Status currentStatus;
@Inject
private Logger log;
/**
* Maps between an activity class name and the list of currently running
* AsyncTasks that were spawned while it was active.
*/
private SparseArray<List<BaseAsyncTask<?, ?, ?>>> mActivityTaskMap;
public AndroidIMSICatcherDetector() {
mActivityTaskMap = new SparseArray<>();
}
@Override
public void onCreate() {
instance = new WeakReference<>(this);
addModule(new AndroidLoggerModule());
addModule(OkHttpModule.withCache(this));
super.onCreate();
RealmConfiguration realmConfiguration = new RealmConfiguration.Builder(this)
.deleteRealmIfMigrationNeeded()
.build();
Realm.setDefaultConfiguration(realmConfiguration);
final Realm realm = Realm.getDefaultInstance();
realm.executeTransactionAsync(
new DefaultDataTransaction(),
new Realm.Transaction.OnSuccess() {
@Override
public void onSuccess() {
log.debug("Loading default data successful");
realm.close();
}
},
new Realm.Transaction.OnError() {
@Override
public void onError(Throwable error) {
log.error("Error loading default data", error);
realm.close();
}
}
);
TinyDB.getInstance().init(getApplicationContext());
TinyDB.getInstance().putBoolean(TinyDbKeys.FINISHED_LOAD_IN_MAP, true);
}
public void removeTask(BaseAsyncTask<?, ?, ?> pTask) {
int key;
for (int i = 0; i < mActivityTaskMap.size(); i++) {
key = mActivityTaskMap.keyAt(i);
List<BaseAsyncTask<?, ?, ?>> tasks = mActivityTaskMap.get(key);
for (BaseAsyncTask<?, ?, ?> lTask : tasks) {
if (lTask.equals(pTask)) {
tasks.remove(lTask);
log.verbose("BaseTask removed:" + pTask.toString());
break;
}
}
if (tasks.size() == 0) {
mActivityTaskMap.remove(key);
return;
}
}
}
public void addTask(Activity activity, BaseAsyncTask<?, ?, ?> pTask) {
if (activity == null) {
return;
}
log.debug("BaseTask addTask activity:" + activity.getClass().getCanonicalName());
int key = activity.getClass().getCanonicalName().hashCode();
List<BaseAsyncTask<?, ?, ?>> tasks = mActivityTaskMap.get(key);
if (tasks == null) {
tasks = new ArrayList<>();
mActivityTaskMap.put(key, tasks);
}
log.verbose("BaseTask added:" + pTask.toString());
tasks.add(pTask);
}
public void detach(Activity activity) {
if (activity == null) {
return;
}
log.debug("BaseTask detach:" + activity.getClass().getCanonicalName());
List<BaseAsyncTask<?, ?, ?>> tasks = mActivityTaskMap.get(activity.getClass().getCanonicalName().hashCode());
if (tasks != null) {
for (BaseAsyncTask<?, ?, ?> task : tasks) {
task.setActivity(null);
}
}
}
public void attach(InjectionAppCompatActivity activity) {
if (activity == null) {
return;
}
log.debug("BaseTask attach:" + activity.getClass().getCanonicalName());
List<BaseAsyncTask<?, ?, ?>> tasks = mActivityTaskMap.get(activity.getClass().getCanonicalName().hashCode());
if (tasks != null) {
for (BaseAsyncTask<?, ?, ?> task : tasks) {
task.setActivity(activity);
}
}
}
/**
* Changes the current status, this will also trigger a local broadcast event
* if the new status is different from the previous one
*/
public void setCurrentStatus(Status status, boolean vibrate, int minVibrateLevel) {
if (status == null) {
status = Status.IDLE;
}
if (status != currentStatus) {
Intent intent = new Intent("StatusChange");
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
if (vibrate && status.ordinal() >= minVibrateLevel) {
((Vibrator) getSystemService(VIBRATOR_SERVICE)).vibrate(100);
}
}
currentStatus = status;
}
/**
* Returns the current status
*/
public Status getStatus() {
if (currentStatus == null) {
return Status.IDLE;
}
return currentStatus;
}
}