/* Android IMSI-Catcher Detector | (c) AIMSICD Privacy Project
* -----------------------------------------------------------
* LICENSE: http://git.io/vki47 | TERMS: http://git.io/vki4o
* -----------------------------------------------------------
*/
package com.secupwn.aimsicd.ui.activities;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.telephony.TelephonyManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import com.secupwn.aimsicd.AndroidIMSICatcherDetector;
import com.secupwn.aimsicd.R;
import com.secupwn.aimsicd.constants.DrawerMenu;
import com.secupwn.aimsicd.service.AimsicdService;
import com.secupwn.aimsicd.service.CellTracker;
import com.secupwn.aimsicd.ui.drawer.DrawerMenuActivityConfiguration;
import com.secupwn.aimsicd.ui.drawer.NavDrawerItem;
import com.secupwn.aimsicd.ui.fragments.AtCommandFragment;
import com.secupwn.aimsicd.ui.fragments.CellInfoFragment;
import com.secupwn.aimsicd.ui.fragments.DbViewerFragment;
import com.secupwn.aimsicd.ui.fragments.DeviceFragment;
import com.secupwn.aimsicd.ui.fragments.MapFragment;
import com.secupwn.aimsicd.utils.AsyncResponse;
import com.secupwn.aimsicd.utils.Cell;
import com.secupwn.aimsicd.utils.GeoLocation;
import com.secupwn.aimsicd.utils.Helpers;
import com.secupwn.aimsicd.utils.Icon;
import com.secupwn.aimsicd.utils.LocationServices;
import com.secupwn.aimsicd.utils.RequestTask;
import java.util.List;
public class MainActivity extends BaseActivity implements AsyncResponse {
private boolean mBound;
private SharedPreferences prefs;
private SharedPreferences.OnSharedPreferenceChangeListener prefListener;
private Editor prefsEditor;
private String mDisclaimerAccepted;
private AimsicdService mAimsicdService;
private DrawerLayout mDrawerLayout;
private ActionBar mActionBar;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private DeviceFragment deviceFragment;
private CellInfoFragment cellInfoFragment;
private AtCommandFragment atCommandFragment;
private DbViewerFragment dbViewerFragment;
private MapFragment mapFragment;
private long mLastPress = 0; // Back press to exit timer
private DrawerMenuActivityConfiguration mNavConf;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
deviceFragment = new DeviceFragment();
cellInfoFragment = new CellInfoFragment();
atCommandFragment = new AtCommandFragment();
dbViewerFragment = new DbViewerFragment();
mapFragment = new MapFragment();
mNavConf = new DrawerMenuActivityConfiguration.Builder(this).build();
mDrawerLayout = (DrawerLayout) findViewById(mNavConf.getDrawerLayoutId());
mDrawerList = (ListView) findViewById(mNavConf.getLeftDrawerId());
mActionBar = getSupportActionBar();
mTitle = getTitle();
mDrawerTitle = getTitle();
mDrawerList.setAdapter(mNavConf.getBaseAdapter());
mDrawerToggle = new ActionBarDrawerToggle(
this, /* host Activity */
mDrawerLayout, /* DrawerLayout object */
R.string.drawer_open, /* "open drawer" description */
R.string.drawer_close /* "close drawer" description */
) {
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
mActionBar.setTitle(mTitle);
invalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
mActionBar.setTitle(mDrawerTitle);
invalidateOptionsMenu();
}
};
// Set the drawer toggle as the DrawerListener
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
mDrawerLayout.setDrawerListener(mDrawerToggle);
mActionBar.setDisplayHomeAsUpEnabled(true);
mActionBar.setHomeButtonEnabled(true);
prefs = getSharedPreferences(AimsicdService.SHARED_PREFERENCES_BASENAME, 0);
/* Pref listener to enable sms detection on pref change */
prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if (key.equals(getString(R.string.adv_user_root_pref_key))) {
SmsDetection();
}
}
};
prefs.registerOnSharedPreferenceChangeListener(prefListener);
mDisclaimerAccepted = getResources().getString(R.string.disclaimer_accepted);
if (!prefs.getBoolean(mDisclaimerAccepted, false)) {
final AlertDialog.Builder disclaimer = new AlertDialog.Builder(this)
.setTitle(R.string.disclaimer_title)
.setMessage(R.string.disclaimer)
.setPositiveButton(R.string.text_agree, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
prefsEditor = prefs.edit();
prefsEditor.putBoolean(mDisclaimerAccepted, true);
prefsEditor.apply();
startService();
}
})
.setNegativeButton(R.string.text_disagree, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
prefsEditor = prefs.edit();
prefsEditor.putBoolean(mDisclaimerAccepted, false);
prefsEditor.apply();
Uri packageUri = Uri.parse("package:com.SecUpwN.AIMSICD");
Intent uninstallIntent =
new Intent(Intent.ACTION_DELETE, packageUri);
startActivity(uninstallIntent);
finish();
if (mAimsicdService != null) {
mAimsicdService.onDestroy();
}
}
});
AlertDialog disclaimerAlert = disclaimer.create();
disclaimerAlert.show();
} else {
startService();
}
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
final String iconType = prefs.getString(getString(R.string.pref_ui_icons_key), "SENSE").toUpperCase();
mActionBar.setIcon(Icon.getIcon(Icon.Type.valueOf(iconType), ((AndroidIMSICatcherDetector) getApplication()).getStatus()));
mDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Unbind from the service
if (mBound) {
unbindService(mConnection);
mBound = false;
}
final String PERSIST_SERVICE = getString(R.string.pref_persistservice_key);
boolean persistService = prefs.getBoolean(PERSIST_SERVICE, false);
if (!persistService) {
stopService(new Intent(this, AimsicdService.class));
}
}
private class DrawerItemClickListener implements ListView.OnItemClickListener {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mDrawerLayout.closeDrawer(mDrawerList);
selectDrawerItem(position);
}
}
void selectDrawerItem(int position) {
NavDrawerItem selectedItem = mNavConf.getNavItems().get(position);
String title = selectedItem.getLabel();
switch (selectedItem.getId()) {
case DrawerMenu.ID.MAIN.PHONE_SIM_DETAILS:
openFragment(deviceFragment);
title = getString(R.string.app_name_short);
break;
case DrawerMenu.ID.MAIN.NEIGHBORING_CELLS:
openFragment(cellInfoFragment);
title = getString(R.string.app_name_short);
break;
case DrawerMenu.ID.MAIN.AT_COMMAND_INTERFACE:
openFragment(atCommandFragment);
title = getString(R.string.app_name_short);
break;
case DrawerMenu.ID.MAIN.DB_VIEWER:
openFragment(dbViewerFragment);
title = getString(R.string.app_name_short);
break;
case DrawerMenu.ID.APPLICATION.UPLOAD_LOCAL_BTS_DATA:
// Request uploading here?
new RequestTask(this, com.secupwn.aimsicd.utils.RequestTask.DBE_UPLOAD_REQUEST).execute("");
// no string needed for csv based upload
break;
case DrawerMenu.ID.MAIN.ANTENNA_MAP_VIEW:
openFragment(mapFragment);
title = getString(R.string.app_name_short);
break;
}
if (selectedItem.getId() == DrawerMenu.ID.DATABASE_SETTINGS.RESET_DB) {
// WARNING! This deletes the entire database, thus any subsequent DB access will FC app.
// Therefore we need to either restart app or run AIMSICDDbAdapter, to rebuild DB.
// See: https://github.com/CellularPrivacy/Android-IMSI-Catcher-Detector/issues/581 and Helpers.java
Helpers.askAndDeleteDb(this);
} else if (selectedItem.getId() == DrawerMenu.ID.APPLICATION.DOWNLOAD_LOCAL_BTS_DATA) {
downloadBtsDataIfApiKeyAvailable();
} else if (selectedItem.getId() == DrawerMenu.ID.APPLICATION.QUIT) {
try {
if (mAimsicdService.isSmsTracking()) {
mAimsicdService.stopSmsTracking();
}
} catch (Exception ee) {
log.warn("Exception in smstracking module: " + ee.getMessage());
}
if (mAimsicdService != null) {
mAimsicdService.onDestroy();
}
finish();
}
mDrawerList.setItemChecked(position, true);
if (selectedItem.updateActionBarTitle()) {
setTitle(title);
}
if (this.mDrawerLayout.isDrawerOpen(this.mDrawerList)) {
mDrawerLayout.closeDrawer(mDrawerList);
}
}
private void openFragment(Fragment fragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
transaction.replace(R.id.content_frame, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
private void downloadBtsDataIfApiKeyAvailable() {
if (CellTracker.OCID_API_KEY != null && !CellTracker.OCID_API_KEY.equals("NA")) {
Cell cell = new Cell();
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String networkOperator = tm.getNetworkOperator();
if (networkOperator != null && !networkOperator.isEmpty()) {
int mcc = Integer.parseInt(networkOperator.substring(0, 3));
cell.setMobileCountryCode(mcc);
int mnc = Integer.parseInt(networkOperator.substring(3));
cell.setMobileNetworkCode(mnc);
log.debug("CELL:: mobileCountryCode=" + mcc + " mobileNetworkCode=" + mnc);
}
GeoLocation loc = mAimsicdService.lastKnownLocation();
if (loc != null) {
Helpers.msgLong(this, getString(R.string.contacting_opencellid_for_data));
cell.setLon(loc.getLongitudeInDegrees());
cell.setLat(loc.getLatitudeInDegrees());
Helpers.getOpenCellData(this, cell, RequestTask.DBE_DOWNLOAD_REQUEST, mAimsicdService);
} else {
Helpers.msgShort(this, getString(R.string.waiting_for_location));
// This uses the LocationServices to get CID/LAC/MNC/MCC to be used
// for grabbing the BTS data from OCID, via their API.
// CID Location Async Output Delegate Interface Implementation
LocationServices.LocationAsync locationAsync
= new LocationServices.LocationAsync();
locationAsync.delegate = this;
locationAsync.execute(
mAimsicdService.getCell().getCellId(),
mAimsicdService.getCell().getLocationAreaCode(),
mAimsicdService.getCell().getMobileNetworkCode(),
mAimsicdService.getCell().getMobileCountryCode());
}
} else {
Helpers.sendMsg(this, getString(R.string.no_opencellid_key_detected));
}
}
@Override
public void processFinish(float[] location) {
log.info("processFinish - location[0]=" + location[0] + " location[1]=" + location[1]);
if (Float.floatToRawIntBits(location[0]) == 0
&& Float.floatToRawIntBits(location[1]) != 0) {
Helpers.msgLong(this, getString(R.string.contacting_opencellid_for_data));
Helpers.getOpenCellData(this, mAimsicdService.getCell(), RequestTask.DBE_DOWNLOAD_REQUEST, mAimsicdService);
} else {
Helpers.msgLong(this, getString(R.string.unable_to_determine_last_location));
}
}
@Override
public void processFinish(List<Cell> cells) {
if (cells != null) {
if (!cells.isEmpty()) {
for (Cell cell : cells) {
log.info("processFinish - Cell =" + cell.toString());
if (cell.isValid()) {
mAimsicdService.setCell(cell);
Intent intent = new Intent(AimsicdService.UPDATE_DISPLAY);
intent.putExtra("update", true);
sendBroadcast(intent);
}
}
}
}
}
@Override
public void setTitle(CharSequence title) {
mTitle = title;
mActionBar.setTitle(mTitle);
}
/**
* Service Connection to bind the activity to the service
*/
private final ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
mAimsicdService = ((AimsicdService.AimscidBinder) service).getService();
mBound = true;
// Check if tracking cell details check location services are still enabled
if (mAimsicdService.isTrackingCell()) {
mAimsicdService.checkLocationServices();
}
if (!mAimsicdService.isSmsTracking() && prefs.getBoolean(getString(R.string.adv_user_root_pref_key), false)) {
/*Auto Start sms detection here if:
* isSmsTracking = false <---- not running
* root sms enabled = true
*
* */
SmsDetection();
}
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
log.warn("Service disconnected");
mBound = false;
}
};
private void startService() {
// don't start service if disclaimer is not accepted
if (!prefs.getBoolean(mDisclaimerAccepted, false)) {
return;
}
if (!mBound) {
// Bind to LocalService
Intent intent = new Intent(MainActivity.this, AimsicdService.class);
//Start Service before binding to keep it resident when activity is destroyed
startService(intent);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
openFragment(deviceFragment);
}
}
/**
* Triggered when GUI is opened
*/
@Override
public void onResume() {
super.onResume();
invalidateOptionsMenu();
startService();
}
/**
* Triggered when GUI is closed/put to background
*/
@Override
public void onPause() {
super.onPause();
}
/**
* Invoked only once during app's lifetime. For successive calls see
* {@link #onPrepareOptionsMenu(Menu)}. Both used primarily to determine checkboxes for tracking
* and detection.
*
* Because the service may not available on app boot, we default to false until the service
* boots. Once that occurs, the checkboxes are driven by the service's status.
*
* @param menu
* @return
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_menu, menu);
MenuItem toggleAttackDetectionMenuItem = menu.findItem(R.id.toggle_attack_detection);
MenuItem toggleCellTrackingMenuItem = menu.findItem(R.id.toggle_cell_tracking);
// The service may not exist on first app boot. Choose sane defaults
if (mAimsicdService == null) {
toggleAttackDetectionMenuItem.setChecked(false);
toggleCellTrackingMenuItem.setChecked(false);
} else {
toggleAttackDetectionMenuItem.setChecked(mAimsicdService.isMonitoringCell());
toggleCellTrackingMenuItem.setChecked(mAimsicdService.isTrackingCell());
}
return true;
}
/**
* Display latest cell tracking & attack detection truth when opening menu over & over
*
* @param menu
* @return
*/
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
// Bail early if there's no service to get the facts from
if (mAimsicdService == null) {
return super.onPrepareOptionsMenu(menu);
}
MenuItem toggleAttackDetectionMenuItem = menu.findItem(R.id.toggle_attack_detection);
MenuItem toggleCellTrackingMenuItem = menu.findItem(R.id.toggle_cell_tracking);
toggleAttackDetectionMenuItem.setChecked(mAimsicdService.isMonitoringCell());
toggleCellTrackingMenuItem.setChecked(mAimsicdService.isTrackingCell());
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.toggle_attack_detection:
monitorCell();
item.setChecked(mAimsicdService.isMonitoringCell());
break;
case R.id.toggle_cell_tracking:
trackCell();
item.setChecked(mAimsicdService.isTrackingCell());
break;
case R.id.settings:
Intent settingsIntent = new Intent(this, SettingsActivity.class);
startActivity(settingsIntent);
break;
case R.id.about:
Intent aboutIntent = new Intent(this, AboutActivity.class);
startActivity(aboutIntent);
break;
case R.id.debugging:
Intent i = new Intent(this, DebugLogs.class);
startActivity(i);
break;
}
return mDrawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
}
/**
* Exit application if Back button is pressed twice
*/
@Override
public void onBackPressed() {
Toast onBackPressedToast = Toast
.makeText(this, R.string.press_once_again_to_exit, Toast.LENGTH_SHORT);
long currentTime = System.currentTimeMillis();
if (currentTime - mLastPress > 5000) {
onBackPressedToast.show();
mLastPress = currentTime;
} else {
onBackPressedToast.cancel();
super.onBackPressed();
try {
if (mAimsicdService.isSmsTracking()) {
mAimsicdService.stopSmsTracking();
}
} catch (Exception ee) {
log.error("Error: Stopping SMS detection : " + ee.getMessage());
}
finish();
}
}
private void SmsDetection() {
boolean root_sms = prefs.getBoolean(getString(R.string.adv_user_root_pref_key), false); // default is false
if (root_sms && !mAimsicdService.isSmsTracking()) {
mAimsicdService.startSmsTracking();
Helpers.msgShort(this, "SMS Detection Started");
log.info("SMS Detection Thread Started");
} else if (!root_sms && mAimsicdService.isSmsTracking()) {
mAimsicdService.stopSmsTracking();
Helpers.msgShort(this, "Sms Detection Stopped");
log.info("SMS Detection Thread Stopped");
}
}
/**
* Cell Information Tracking - Enable/Disable
*/
private void trackCell() {
mAimsicdService.setCellTracking(!mAimsicdService.isTrackingCell());
}
/**
* Cell Information Monitoring - Enable/Disable
*/
private void monitorCell() {
mAimsicdService.setCellMonitoring(!mAimsicdService.isMonitoringCell());
}
/**
* FemtoCell Detection (CDMA Phones ONLY) - Enable/Disable
*/
private void trackFemtocell() {
mAimsicdService.setTrackingFemtocell(!mAimsicdService.isTrackingFemtocell());
}
public void onStop() {
super.onStop();
((AndroidIMSICatcherDetector) getApplication()).detach(this);
}
@Override
public void onStart() {
super.onStart();
((AndroidIMSICatcherDetector) getApplication()).attach(this);
}
}