diff options
Diffstat (limited to 'app/src/fil/libre/repwifiapp/activities/MainActivity.java')
-rw-r--r-- | app/src/fil/libre/repwifiapp/activities/MainActivity.java | 545 |
1 files changed, 432 insertions, 113 deletions
diff --git a/app/src/fil/libre/repwifiapp/activities/MainActivity.java b/app/src/fil/libre/repwifiapp/activities/MainActivity.java index 7a22416..14f33e9 100644 --- a/app/src/fil/libre/repwifiapp/activities/MainActivity.java +++ b/app/src/fil/libre/repwifiapp/activities/MainActivity.java @@ -1,5 +1,5 @@ // -// Copyright 2017 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> +// Copyright 2017, 2018 Filippo "Fil" Bergamo <fil.bergamo@riseup.net> // // This file is part of RepWifiApp. // @@ -20,64 +20,80 @@ package fil.libre.repwifiapp.activities; -import java.net.SocketException; -import fil.libre.repwifiapp.ActivityLauncher; -import fil.libre.repwifiapp.Commons; -import fil.libre.repwifiapp.R; -import fil.libre.repwifiapp.ActivityLauncher.RequestCode; -import fil.libre.repwifiapp.helpers.AccessPointInfo; -import fil.libre.repwifiapp.helpers.ConnectionStatus; -import fil.libre.repwifiapp.helpers.NetworkManager; -import fil.libre.repwifiapp.helpers.OpenVpnManager; -import fil.libre.repwifiapp.helpers.RootCommand; -import fil.libre.repwifiapp.helpers.Utils; -import fil.libre.repwifiapp.helpers.WpaSupplicant; -import android.os.Bundle; +import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.AssetManager; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.hardware.usb.UsbManager; +import android.os.Bundle; +import android.os.Parcelable; import android.util.Log; import android.view.View; +import android.widget.Button; import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.RelativeLayout.LayoutParams; +import android.widget.TextView; import android.widget.Toast; +import fil.libre.repwifiapp.ActivityLauncher; +import fil.libre.repwifiapp.ActivityLauncher.RequestCode; +import fil.libre.repwifiapp.Commons; +import fil.libre.repwifiapp.Prefs; +import fil.libre.repwifiapp.R; +import fil.libre.repwifiapp.Utils; +import fil.libre.repwifiapp.helpers.Logger; +import fil.libre.repwifiapp.helpers.RootCommand; +import fil.libre.repwifiapp.network.AccessPointInfo; +import fil.libre.repwifiapp.network.ConnectionResult; +import fil.libre.repwifiapp.network.ConnectionStatus; +import fil.libre.repwifiapp.network.Engine; +import fil.libre.repwifiapp.network.NetworkManager; +import fil.libre.repwifiapp.network.WpaCli; +import fil.libre.repwifiapp.network.WpaSupplicant; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.SocketException; -public class MainActivity extends MenuEnabledActivity { +public class MainActivity extends VpnAndConnectionBoundActivity{ private ActivityLauncher launcher = new ActivityLauncher(this); private BroadcastReceiver detachReceiver; - + private ConnectionStatus status = null; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - if (!Commons.init(this)) { - Utils.logDebug("Failed to initialize Commons. Aborting."); - finish(); - return; - } + Commons.init(getApplicationContext()); - if (! Commons.storage.updateStorageVersion()){ - Utils.logError("Failed to convert storage file to new version!"); + if (!NetworkManager.updateStorageVersion()) { + Logger.logError("Failed to convert storage file to new version!"); } - - setImage(); + + toggleStatusAppearance(false); setUsbDeviceMonitor(); setVersionOnTitle(); - - OpenVpnManager.initialize(this); + + if (isSystemApp()) { + setTitle(getTitle() + " (sysapp)"); + } } @Override public void onStart() { super.onStart(); - Utils.logDebug("Main onStart()"); - - Commons.updateNotification(this); + Logger.logDebug("Main onStart()"); if (handleIntent()) { // app called for a specific intent. @@ -88,14 +104,17 @@ public class MainActivity extends MenuEnabledActivity { checkConditions(); - ConnectionStatus status = Commons.connectionEngine.getConnectionStatus(); - if (status != null && status.isConnected()) { - Utils.logDebug("Main about to launch status activity..."); - launcher.launchStatusActivity(status); + if (isServiceBound()) { + requestStatusUpdate(); } - Utils.logDebug("Main onStart() returning."); + Logger.logDebug("Main onStart() returning."); + + } + @Override + public void onSaveInstanceState(Bundle savedInstanceState) { + super.onSaveInstanceState(savedInstanceState); } private boolean handleIntent() { @@ -126,53 +145,62 @@ public class MainActivity extends MenuEnabledActivity { @Override public void onActivityResult(int requestCode, int resultCode, Intent intent) { - Utils.logDebug("Main onActivityResult(): ", 1); + Logger.logDebug("Main onActivityResult(): "); if (intent == null) { return; } - if (resultCode != RESULT_OK) { + if (resultCode != RESULT_OK && requestCode != RequestCode.VPN_PERMISSION_CONN) { return; } AccessPointInfo i = null; if (intent.hasExtra(ActivityLauncher.EXTRA_APINFO)) { Bundle xtras = intent.getExtras(); - i = (AccessPointInfo) xtras.getSerializable(ActivityLauncher.EXTRA_APINFO); + i = (AccessPointInfo) xtras.getParcelable(ActivityLauncher.EXTRA_APINFO); } switch (requestCode) { case RequestCode.PASS_INPUT: + Logger.logDebug("ReqCode: PASS_INPUT"); handleResultSetPass(i); break; case RequestCode.SELECT_CONN: + Logger.logDebug("ReqCode: SELECT_CONN"); boolean rescan = intent.getExtras().getBoolean(ActivityLauncher.EXTRA_RESCAN); handleResultSelect(i, rescan); break; case RequestCode.CONNECT: - boolean conres = intent.getExtras().getBoolean(ActivityLauncher.EXTRA_BOOLEAN); + Logger.logDebug("ReqCode: CONNECT"); + ConnectionResult conres = (ConnectionResult) intent.getExtras().getParcelable( + ActivityLauncher.EXTRA_CONNRES); handleFinishedConnecting(conres, i); break; - case RequestCode.NETWORKS_GET: - AccessPointInfo[] nets = (AccessPointInfo[]) intent.getExtras().getSerializable( + Logger.logDebug("ReqCode: NETWORKS_GET"); + Parcelable[] p = intent.getExtras().getParcelableArray( ActivityLauncher.EXTRA_APINFO_ARR); + AccessPointInfo[] nets = AccessPointInfo.fromParcellableArray(p); launcher.launchSelectActivity(nets, true, false); + break; case RequestCode.STATUS_SHOW: + Logger.logDebug("ReqCode: STATUS_SHOW"); // do nothing break; case RequestCode.SELECT_DETAILS: + Logger.logDebug("ReqCode: SELECT_DETAILS"); launcher.launchDetailsActivity(i); break; case RequestCode.DETAILS_SHOW: + Logger.logDebug("ReqCode: DETAILS_SHOW"); boolean del = intent.getExtras().getBoolean(ActivityLauncher.EXTRA_DELETE); if (del) { deleteNetwork(i); @@ -180,13 +208,14 @@ public class MainActivity extends MenuEnabledActivity { break; case RequestCode.CONNECT_HIDDEN: + Logger.logDebug("ReqCode: CONNECT_HIDDEN"); if (i != null) { + Logger.logDebug("NetworkInfo NOT null, handling result"); handleResultSelect(i, false); } break; - default: break; @@ -207,22 +236,118 @@ public class MainActivity extends MenuEnabledActivity { setTitle(getTitle() + " - v." + vers); } catch (Exception e) { - Utils.logError("Error while setting version on MainActivity's title.", e); + Logger.logError("Error while setting version on MainActivity's title.", e); } } - private void setImage() { + private void showStatus(ConnectionStatus status) { + + Logger.logDebug("MainActivity.showStatus()"); - ImageView img = (ImageView) findViewById(R.id.img_logo); + String msg = ""; + this.status = status; try { - Drawable d = Drawable.createFromStream(getAssets().open("repwifi-logo-0.png"), null); - img.setImageDrawable(d); + + if (status == null) { + msg = getString(R.string.text_status) + ": [NULL]"; + toggleStatusAppearance(false); + + } else if (this.status.isConnected()) { + Logger.logDebug("showStatus isConnected,showing buttons"); + msg = getString(R.string.msg_connected_to) + " " + status.SSID; + toggleStatusAppearance(true); + + } else { + Logger.logDebug("showStatus status Else"); + msg = getString(R.string.msg_disconnected); + toggleStatusAppearance(false); + } + } catch (Exception e) { - Utils.logError("Error while loading logo image", e); + Logger.logError("Exception on showStatus", e); + msg = "[ERORR]"; } + TextView view = (TextView) findViewById(R.id.txt_status); + view.setText(msg); + + } + + private void toggleStatusAppearance(boolean connected) { + + try { + Button b = (Button) findViewById(R.id.btn_disconnect); + Button i = (Button) findViewById(R.id.btn_info); + ImageView img = (ImageView) findViewById(R.id.img_logo); + + LayoutParams lp = (LayoutParams) img.getLayoutParams(); + + b.setEnabled(connected); + i.setEnabled(connected); + + if (connected) { + b.setVisibility(View.VISIBLE); + i.setVisibility(View.VISIBLE); + lp.removeRule(RelativeLayout.CENTER_HORIZONTAL); + + } else { + b.setVisibility(View.INVISIBLE); + i.setVisibility(View.INVISIBLE); + lp.addRule(RelativeLayout.CENTER_HORIZONTAL); + } + + setLogoDrawable(img, connected); + img.setLayoutParams(lp); + + } catch (Exception e) { + Logger.logError("Error while setting status appearance", e); + + } + + } + + BitmapDrawable logoConn; + BitmapDrawable logoDisc; + + public void setLogoDrawable(ImageView img, boolean connected) { + + img.setImageDrawable(null); + System.gc(); + + try { + + String res = "repwifi-logo-0-small.png"; + BitmapDrawable logo = logoConn; + if (!connected) { + logo = logoDisc; + res = "repwifi-logo-1-small.png"; + } + + AssetManager am = getAssets(); + InputStream s = am.open(res); + + if (logo == null) { + logo = (BitmapDrawable) Drawable.createFromStream(s, res); + } + img.setImageDrawable(logo); + + s.close(); + } catch (IOException e) { + } + + } + + public void onBtnDisconnectClick(View v) { + + disconnectVpn(); + sendCmdDisconnect(); + + } + + public void onBtnInfoClick(View v) { + launcher.launchStatusActivity(this.status); } private void setUsbDeviceMonitor() { @@ -245,9 +370,17 @@ public class MainActivity extends MenuEnabledActivity { registerReceiver(detachReceiver, filt2); } - private boolean checkConditions() { + private boolean checkConditions(boolean serviceStarted) { + // second chance to have the service bound: + boolean conds = (checkRootEnabled() && checkIsSystemApp() && checkInterface(true)); + if (serviceStarted) { + conds = conds && isServiceBound(); + } + return conds; + } - return (checkRootEnabled() && checkInterface(true)); + private boolean checkConditions() { + return checkConditions(false); } private boolean checkInterface(boolean alert) { @@ -256,16 +389,16 @@ public class MainActivity extends MenuEnabledActivity { String msg = ""; try { - res = Commons.connectionEngine.isInterfaceAvailable(WpaSupplicant.INTERFACE_NAME); + res = Engine.isInterfaceAvailable(WpaSupplicant.INTERFACE_NAME); } catch (SocketException e) { - Utils.logError("SocketException during isInterfaceAvailable()", e); + Logger.logError("SocketException during isInterfaceAvailable()", e); msg = "Error while retrieving interface list!"; res = false; } if (res == false && alert) { msg = getResources().getString(R.string.msg_interface_not_found); - Commons.showMessage(msg, this); + Utils.showMessage(msg, this); } return res; @@ -283,7 +416,7 @@ public class MainActivity extends MenuEnabledActivity { try { excode = su.testRootAccess(); } catch (Exception e) { - Utils.logError("Error while trying to get first Super User access.", e); + Logger.logError("Error while trying to get first Super User access.", e); excode = -1; result = false; } @@ -310,7 +443,7 @@ public class MainActivity extends MenuEnabledActivity { } if (!result) { - Commons.showMessage(msg, this); + Utils.showMessage(msg, this); } return result; @@ -328,7 +461,7 @@ public class MainActivity extends MenuEnabledActivity { if (i.needsPassword()) { // try to fetch network's configuration from storage - AccessPointInfo fromStorage = Commons.storage.getSavedNetwork(i); + AccessPointInfo fromStorage = NetworkManager.getSavedNetwork(i); if (fromStorage == null) { launcher.launchPasswordActivity(i); @@ -341,6 +474,8 @@ public class MainActivity extends MenuEnabledActivity { } + // disconnect any vpn before connecting to a new network + disconnectVpn(); launcher.launchLongTaskActivityConnect(i); } @@ -350,44 +485,70 @@ public class MainActivity extends MenuEnabledActivity { launcher.launchLongTaskActivityConnect(i); } - private void handleFinishedConnecting(boolean connectionResult, AccessPointInfo info) { + private void handleFinishedConnecting(ConnectionResult connectionResult, AccessPointInfo info) { - if (connectionResult && info.needsPassword()) { + Logger.logDebug("handleFinishedConnecting"); - ConnectionStatus status = Commons.connectionEngine.getConnectionStatus(); - if (status != null) { - // update APinfo with the right BSSID - info.setBssid(status.BSSID); - } + String toastText = null; + int res = connectionResult.getResult(); + ConnectionStatus status = connectionResult.getStatus(); - // Save network - if (Commons.storage.save(info)) { - Toast toast2 = Toast.makeText(getApplicationContext(), - getString(R.string.msg_network_saved), Toast.LENGTH_LONG); - toast2.show(); + switch (res) { - } else { - Toast toast2 = Toast.makeText(getApplicationContext(), - getString(R.string.msg_network_save_fail), Toast.LENGTH_LONG); - toast2.show(); - } + case ConnectionResult.CONN_OK: - // show status - launcher.launchStatusActivity(status); + Logger.logDebug("About to launch VPN on successful connection result."); + beginConnectVpn(status.getNetworkDetails()); + + + break; - } else { - // alert that connection failed - Toast toast = Toast.makeText(getApplicationContext(), - getString(R.string.msg_connect_fail), Toast.LENGTH_LONG); + case ConnectionResult.CONN_GW_FAIL: + Logger.logDebug("Result code CONN_GW_FAIL"); + toastText = getString(R.string.msg_gw_failed); + break; + + case ConnectionResult.CONN_TIMEOUT: + // probable wrong password: + handleConnectionTimeout(info); + break; + + default: + Logger.logDebug("Result code: " + res); + toastText = getString(R.string.msg_connect_fail); + break; + + } + + if (toastText != null) { + Toast toast = Toast.makeText(getApplicationContext(), toastText, Toast.LENGTH_LONG); toast.show(); } + + showStatus(status); + + } + + private void handleConnectionTimeout(AccessPointInfo info) { + // reset wpa_supplicant's state + WpaCli.disconnect(); + if (!WpaCli.terminateSupplicant()) { + WpaSupplicant.kill(); + } + + if (info.needsPassword()) { + // prompt user for password retry: + launcher.launchPasswordActivity(info, getString(R.string.msg_connection_timeout)); + } else { + Utils.showMessage(getString(R.string.msg_connection_timeout_nopass), this); + } + } private void deleteNetwork(AccessPointInfo info) { - NetworkManager manager = new NetworkManager(Commons.getNetworkStorageFile()); String msg = ""; - if (manager.remove(info)) { + if (NetworkManager.remove(info)) { msg = getString(R.string.msg_netinfo_deleted); } else { msg = getString(R.string.msg_netinfo_delete_fail); @@ -401,10 +562,11 @@ public class MainActivity extends MenuEnabledActivity { private void handleUsbEvent(boolean detached) { if (detached && !checkInterface(false)) { - // device disconnected, update the status bar: - Commons.updateNotification(this); + // device disconnected: + // clear back-end state and update status. + disconnectVpn(); - } else if (Commons.isAutoConnectEnabled()) { + } else if (isAutoConnectEnabled()) { try { @@ -417,7 +579,7 @@ public class MainActivity extends MenuEnabledActivity { msWaited += 100; if (checkInterface(false)) { - autoConnect(); + sendCmdAutoconnect(); return; } } @@ -429,56 +591,213 @@ public class MainActivity extends MenuEnabledActivity { } - } + requestStatusUpdate(); - private void autoConnect() { + } - try { + private boolean isAutoConnectEnabled() { + return Prefs.getBoolean(getApplicationContext(), Prefs.PREF_AUTOCONNECT, false); + } - AccessPointInfo[] nets = Commons.connectionEngine.getAvailableNetworks(); - if (nets == null || nets.length == 0) { - return; - } + private void doScan() { + if (checkConditions(true)) { + launcher.launchLongTaskActivityScan(); + } + } - for (AccessPointInfo i : nets) { + public void btnScanClick(View v) { + doScan(); + } - if (Commons.storage.isKnown(i)) { - launcher.launchLongTaskActivityConnect(i); - return; - } + public void btnHiddenClick(View v) { + if (checkConditions(true)) { + launcher.launchInputSsidActivity(); + } + } - } + public void btnManageClick(View v) { + launcher.launchSelectActivity(null, false, true); + } - // if no network is known, shows available networks to the user. - launcher.launchSelectActivity(nets, true, false); + private boolean checkIsSystemApp() { - } catch (Exception e) { - Utils.logError("Error while autoconnecting", e); - Commons.showMessage(getString(R.string.msg_autoconnect_error), this); + if (isSystemApp()) { + return true; + } else { + promtpMakeSystemApp(); + return false; } + } + + private void promtpMakeSystemApp() { + + String msg = getString(R.string.msg_make_system_app); + AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this, + R.style.Theme_RepWifiDialogTheme); + dlgAlert.setMessage(msg); + dlgAlert.setPositiveButton(getString(android.R.string.ok), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + confirmMakeSystemApp(); + return; + } + }); + dlgAlert.setNegativeButton(getString(android.R.string.cancel), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + return; + } + }); + + dlgAlert.setCancelable(false); + AlertDialog diag = dlgAlert.create(); + + diag.show(); } - private void doScan() { - if (checkConditions()) { - launcher.launchLongTaskActivityScan(); + private void confirmMakeSystemApp() { + String msg = getString(R.string.msg_confirm_make_system_app); + AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this, + R.style.Theme_RepWifiDialogTheme); + dlgAlert.setMessage(msg); + dlgAlert.setPositiveButton(getString(android.R.string.yes), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + makeSystemApp(); + return; + } + }); + dlgAlert.setNegativeButton(getString(android.R.string.no), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + return; + } + }); + + dlgAlert.setCancelable(false); + AlertDialog diag = dlgAlert.create(); + + diag.show(); + } + + private boolean isSystemApp() { + + PackageManager pm = getPackageManager(); + boolean isSystem = false; + try { + ApplicationInfo ai = pm.getApplicationInfo(getPackageName(), 0); + + isSystem = ((ai.flags & ApplicationInfo.FLAG_SYSTEM) == 1); + + } catch (NameNotFoundException e) { + // always succeeds, as we use our own package } + return isSystem; + } - public void btnScanClick(View v) { - doScan(); + public static final String SYS_FOLDER = "/system"; + public static final String SYS_APP_FOLDER = "/system/priv-app"; + private static final String SYSAPP_SCRIPT_FNAME = "make-system-app.sh"; + + private boolean makeSystemApp() { + + PackageManager pm = getPackageManager(); + String pkgName = getPackageName(); + File currentSourceDir = null; + try { + ApplicationInfo ai = pm.getApplicationInfo(pkgName, 0); + currentSourceDir = new File(ai.sourceDir); + + } catch (NameNotFoundException e) { + }// always succeeds, as we use our own package + + String parentFolder = currentSourceDir.getParentFile().getName(); + if (!parentFolder.contains(pkgName)) { + // use the plain package name as a parent folder for the apk + parentFolder = pkgName; + } + + String targetDir = SYS_APP_FOLDER + "/" + parentFolder; + + // get own data directory: + File ownDir = getFilesDir(); + File scriptFile = new File(ownDir, SYSAPP_SCRIPT_FNAME); + String conts = Utils.rawResourceAsString(getApplicationContext(), R.raw.make_system_app); + + if (conts == null) { + Logger.logError("Error while opening script from raw resources."); + return false; + } + + if (!Utils.writeFile(scriptFile.getAbsolutePath(), conts, true)) { + Logger.logError("Failed to write script contents to file."); + return false; + } + + Logger.logDebug("Starting script to make myself a system app..."); + + String cmd = "bash \"" + scriptFile.getAbsolutePath() + "\"" + " \"" + targetDir + "\"" + + " \"" + currentSourceDir.getAbsolutePath() + "\"" + " \"" + SYS_FOLDER + + "\""; + + return RootCommand.executeRootCmd(cmd); + } + + + @Override + protected void onMsgDisconnectReport(ConnectionStatus status) { + String msg = ""; - public void btnHiddenClick(View v) { + if (status != null && !status.isConnected()) { + msg = getString(R.string.msg_disconnected); + } else { + msg = getString(R.string.msg_disconnect_fail); + } - if (checkConditions()) { - launcher.launchInputSsidActivity(); + Toast.makeText(this, msg, Toast.LENGTH_LONG).show(); + showStatus(status); + + } + + @Override + protected void onMsgAutoconnectReport(AccessPointInfo[] infos) { + if (infos != null && infos.length > 0) { + launcher.launchSelectActivity(infos, true, false); } + } + @Override + protected void onMsgStatusChange(ConnectionStatus status) { + Logger.logDebug("Received status update from service."); + showStatus(status); } - public void btnManageClick(View v) { - launcher.launchSelectActivity(null, false, true); + @Override + protected void onManagementServiceConnected() { + super.onManagementServiceConnected(); + requestStatusUpdate(); + } + + @Override + protected void onStop() { + super.onStop(); + } + + @Override + public void onDestroy() { + + if (detachReceiver != null) { + unregisterReceiver(detachReceiver); + } + + super.onDestroy(); } } |