From a2d41e4f790ffc04fe65ab922fdcc6394924ddfa Mon Sep 17 00:00:00 2001 From: Nathan Freitas Date: Fri, 28 Oct 2011 00:29:57 -0400 Subject: [PATCH 01/19] fixes geoip settings, and other small server config changes --- .../android/service/TorBinaryInstaller.java | 56 ++++++++---------- .../android/service/TorService.java | 58 +++++++++---------- .../android/service/TorServiceConstants.java | 7 ++- .../android/service/TorServiceUtils.java | 44 +++----------- .../android/service/TorTransProxy.java | 6 +- 5 files changed, 67 insertions(+), 104 deletions(-) diff --git a/src/org/torproject/android/service/TorBinaryInstaller.java b/src/org/torproject/android/service/TorBinaryInstaller.java index ba6ab3fa..72f4ad30 100644 --- a/src/org/torproject/android/service/TorBinaryInstaller.java +++ b/src/org/torproject/android/service/TorBinaryInstaller.java @@ -13,6 +13,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.torproject.android.R; +import org.torproject.android.TorConstants; import android.content.Context; import android.util.Log; @@ -34,43 +35,34 @@ public class TorBinaryInstaller implements TorServiceConstants { /* * Extract the Tor binary from the APK file using ZIP */ - public boolean installFromRaw () + public boolean installFromRaw () throws IOException { - boolean result = false; - - try - { - InputStream is; - - is = context.getResources().openRawResource(R.raw.toraa); - streamToFile(is,installFolder, TOR_BINARY_ASSET_KEY, false); + InputStream is; - is = context.getResources().openRawResource(R.raw.torab); - streamToFile(is,installFolder, TOR_BINARY_ASSET_KEY, true); - - is = context.getResources().openRawResource(R.raw.torac); - streamToFile(is,installFolder, TOR_BINARY_ASSET_KEY, true); - - is = context.getResources().openRawResource(R.raw.torad); - streamToFile(is,installFolder, TOR_BINARY_ASSET_KEY, true); - - is = context.getResources().openRawResource(R.raw.torrc); - streamToFile(is,installFolder, TORRC_ASSET_KEY, false); + is = context.getResources().openRawResource(R.raw.toraa); + streamToFile(is,installFolder, TOR_BINARY_ASSET_KEY, false); - is = context.getResources().openRawResource(R.raw.privoxy); - streamToFile(is,installFolder, PRIVOXY_ASSET_KEY, false); + is = context.getResources().openRawResource(R.raw.torab); + streamToFile(is,installFolder, TOR_BINARY_ASSET_KEY, true); - is = context.getResources().openRawResource(R.raw.privoxy_config); - streamToFile(is,installFolder, PRIVOXYCONFIG_ASSET_KEY, false); + is = context.getResources().openRawResource(R.raw.torac); + streamToFile(is,installFolder, TOR_BINARY_ASSET_KEY, true); + + is = context.getResources().openRawResource(R.raw.torad); + streamToFile(is,installFolder, TOR_BINARY_ASSET_KEY, true); + + is = context.getResources().openRawResource(R.raw.torrc); + streamToFile(is,installFolder, TORRC_ASSET_KEY, false); - } - catch (IOException ioe) - { - Log.e(TAG, "unable to install tor binaries from raw", ioe); - return false; - } - + is = context.getResources().openRawResource(R.raw.privoxy); + streamToFile(is,installFolder, PRIVOXY_ASSET_KEY, false); + + is = context.getResources().openRawResource(R.raw.privoxy_config); + streamToFile(is,installFolder, PRIVOXYCONFIG_ASSET_KEY, false); + + is = context.getResources().openRawResource(R.raw.geoip); + streamToFile(is,installFolder, GEOIP_ASSET_KEY, false); return true; } @@ -132,7 +124,7 @@ public class TorBinaryInstaller implements TorServiceConstants { } catch (IOException ex) { - Log.e(TAG, "error copying binary", ex); + Log.e(TorConstants.TAG, "error copying binary", ex); } } diff --git a/src/org/torproject/android/service/TorService.java b/src/org/torproject/android/service/TorService.java index 0f9cee3b..70b7c9c9 100644 --- a/src/org/torproject/android/service/TorService.java +++ b/src/org/torproject/android/service/TorService.java @@ -17,12 +17,12 @@ import net.freehaven.tor.control.ConfigEntry; import net.freehaven.tor.control.EventHandler; import net.freehaven.tor.control.TorControlConnection; -import org.torproject.android.AppManager; import org.torproject.android.Orbot; -import org.torproject.android.ProcessSettingsAsyncTask; import org.torproject.android.R; import org.torproject.android.TorConstants; import org.torproject.android.Utils; +import org.torproject.android.settings.AppManager; +import org.torproject.android.settings.ProcessSettingsAsyncTask; import android.app.AlertDialog; import android.app.Notification; @@ -40,7 +40,7 @@ import android.os.RemoteException; import android.preference.PreferenceManager; import android.util.Log; -public class TorService extends Service implements TorServiceConstants, Runnable, EventHandler +public class TorService extends Service implements TorServiceConstants, TorConstants, Runnable, EventHandler { public static boolean ENABLE_DEBUG_LOG = false; @@ -516,24 +516,14 @@ public class TorService extends Service implements TorServiceConstants, Runnable private boolean setupTransProxy (boolean activate) throws Exception { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - boolean hasRoot; - - if (prefs.contains("has_root")) - { - hasRoot = prefs.getBoolean("has_root",false); - } - else - { - hasRoot = TorServiceUtils.checkRootAccess(); - Editor pEdit = prefs.edit(); - pEdit.putBoolean("has_root",hasRoot); - pEdit.commit(); - } + + boolean hasRoot = prefs.getBoolean(PREF_HAS_ROOT,false); if (!hasRoot) - return false; - - if (activate) + { + + } + else if (activate) { boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false); @@ -748,7 +738,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable { logNotice( "Connecting to control port: " + TOR_CONTROL_PORT); - String baseMessage = getString(R.string.tor_process_connecting); + String baseMessage = getString(R.string.tor_process_starting); sendCallbackStatusMessage(baseMessage); torConnSocket = new Socket(IP_LOCALHOST, TOR_CONTROL_PORT); @@ -756,7 +746,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable // conn.authenticate(new byte[0]); // See section 3.2 - sendCallbackStatusMessage(getString(R.string.tor_process_connecting_step2)); logNotice( "SUCCESS connected to control port"); @@ -772,7 +761,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable logNotice( "SUCCESS authenticated to control port"); - sendCallbackStatusMessage(getString(R.string.tor_process_connecting_step2) + getString(R.string.tor_process_connecting_step3)); + sendCallbackStatusMessage(getString(R.string.tor_process_starting) + ' ' + getString(R.string.tor_process_complete)); addEventHandler(); @@ -785,7 +774,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable conn = null; Log.d(TAG,"Attempt: Error connecting to control port: " + ce.getLocalizedMessage(),ce); - sendCallbackStatusMessage(getString(R.string.tor_process_connecting_step4)); + sendCallbackStatusMessage(getString(R.string.tor_process_waiting)); Thread.sleep(1000); @@ -910,14 +899,14 @@ public class TorService extends Service implements TorServiceConstants, Runnable if (msg.indexOf(TOR_CONTROL_PORT_MSG_BOOTSTRAP_DONE)!=-1) { currentStatus = STATUS_ON; + showToolbarNotification (getString(R.string.status_activated),NOTIFY_ID,R.drawable.tornotificationon); getHiddenServiceHostname (); } - - - showToolbarNotification (getString(R.string.status_activated),NOTIFY_ID,R.drawable.tornotificationon); + + sendCallbackStatusMessage (msg); @@ -1273,7 +1262,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable private boolean applyPreferences () throws RemoteException { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); ENABLE_DEBUG_LOG = prefs.getBoolean("pref_enable_logging",false); @@ -1284,9 +1272,7 @@ public class TorService extends Service implements TorServiceConstants, Runnable //boolean autoUpdateBridges = prefs.getBoolean(TorConstants.PREF_BRIDGES_UPDATED, false); boolean becomeRelay = prefs.getBoolean(TorConstants.PREF_OR, false); - boolean ReachableAddresses = prefs.getBoolean(TorConstants.PREF_REACHABLE_ADDRESSES,false); - boolean enableHiddenServices = prefs.getBoolean("pref_hs_enable", false); boolean enableStrictNodes = prefs.getBoolean("pref_strict_nodes", false); @@ -1294,6 +1280,18 @@ public class TorService extends Service implements TorServiceConstants, Runnable String exitNodes = prefs.getString("pref_exit_nodes", null); String excludeNodes = prefs.getString("pref_exclude_nodes", null); + String proxyType = prefs.getString("pref_proxy_type", null); + if (proxyType != null) + { + String proxyHost = prefs.getString("pref_proxy_host", null); + String proxyPort = prefs.getString("pref_proxy_port", null); + + if (proxyHost != null && proxyPort != null) + { + mBinder.updateConfiguration(proxyType + "Proxy", proxyHost + ':' + proxyPort, false); + } + } + if (currentStatus == STATUS_ON) { //reset iptables rules in active mode @@ -1308,6 +1306,8 @@ public class TorService extends Service implements TorServiceConstants, Runnable } } + File fileGeoIP = new File(appBinHome,"geoip"); + mBinder.updateConfiguration("GeoIPFile", fileGeoIP.getAbsolutePath(), false); mBinder.updateConfiguration("EntryNodes", entranceNodes, false); mBinder.updateConfiguration("ExitNodes", exitNodes, false); mBinder.updateConfiguration("ExcludeNodes", excludeNodes, false); diff --git a/src/org/torproject/android/service/TorServiceConstants.java b/src/org/torproject/android/service/TorServiceConstants.java index 4f58dde8..759d0ced 100644 --- a/src/org/torproject/android/service/TorServiceConstants.java +++ b/src/org/torproject/android/service/TorServiceConstants.java @@ -4,11 +4,9 @@ package org.torproject.android.service; public interface TorServiceConstants { - public final static String TAG = "ORBOT"; public final static String TOR_APP_USERNAME = "org.torproject.android"; - public final static String ASSETS_BASE = "assets/"; //home directory of Android application @@ -27,7 +25,10 @@ public interface TorServiceConstants { //privoxy.config public final static String PRIVOXYCONFIG_ASSET_KEY = "privoxy.config"; - + + //geoip data file asset key + public final static String GEOIP_ASSET_KEY = "geoip"; + //various console cmds public final static String SHELL_CMD_CHMOD = "chmod"; public final static String SHELL_CMD_KILL = "kill -9"; diff --git a/src/org/torproject/android/service/TorServiceUtils.java b/src/org/torproject/android/service/TorServiceUtils.java index 657d525d..51d6378c 100644 --- a/src/org/torproject/android/service/TorServiceUtils.java +++ b/src/org/torproject/android/service/TorServiceUtils.java @@ -9,47 +9,15 @@ import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.util.StringTokenizer; +import org.torproject.android.TorConstants; + import android.util.Log; public class TorServiceUtils implements TorServiceConstants { - /** - * Check if we have root access - * @return boolean true if we have root - */ - /* - public static boolean checkRootAccess() { - - - StringBuilder log = new StringBuilder(); - - try { - - // Run an empty script just to check root access - String[] cmd = {"exit 0"}; - int exitCode = TorServiceUtils.doShellCommand(cmd, log, true, true); - if (exitCode == 0) { - - return true; - } - - } catch (IOException e) { - //this means that there is no root to be had (normally) so we won't log anything - TorService.logException("Error checking for root access",e); - - } - catch (Exception e) { - TorService.logException("Error checking for root access",e); - //this means that there is no root to be had (normally) - } - - TorService.logMessage("Could not acquire root permissions"); - return false; - } - */ - - public static boolean checkRootAccess(){ + public static boolean isRootPossible() + { StringBuilder log = new StringBuilder(); @@ -79,6 +47,8 @@ public class TorServiceUtils implements TorServiceConstants { } TorService.logMessage("Could not acquire root permissions"); + + return false; } @@ -102,7 +72,7 @@ public class TorServiceUtils implements TorServiceConstants { } catch (Exception e2) { - Log.w(TAG,"Unable to get proc id for: " + command,e2); + Log.w(TorConstants.TAG,"Unable to get proc id for: " + command,e2); } } diff --git a/src/org/torproject/android/service/TorTransProxy.java b/src/org/torproject/android/service/TorTransProxy.java index de8ea83c..2c1119a4 100644 --- a/src/org/torproject/android/service/TorTransProxy.java +++ b/src/org/torproject/android/service/TorTransProxy.java @@ -2,16 +2,16 @@ package org.torproject.android.service; import java.io.File; -import org.torproject.android.TorifiedApp; +import org.torproject.android.TorConstants; +import org.torproject.android.settings.TorifiedApp; import android.content.Context; import android.util.Log; public class TorTransProxy implements TorServiceConstants { - private final static String TAG = TorServiceConstants.TAG; + private final static String TAG = TorConstants.TAG; - public static int purgeIptables(Context context) throws Exception { From a85f5b95527d9a1a137091bb64121f31753c51db Mon Sep 17 00:00:00 2001 From: Nathan Freitas Date: Fri, 28 Oct 2011 00:31:08 -0400 Subject: [PATCH 02/19] new wizard interface nearly complete --- src/org/torproject/android/AppManager.java | 272 ----------- .../android/ConfigureTransProxy.java | 183 -------- src/org/torproject/android/LotsaText.java | 133 ------ src/org/torproject/android/Orbot.java | 75 ++-- src/org/torproject/android/Permissions.java | 229 ---------- .../android/ProcessSettingsAsyncTask.java | 32 -- .../android/SettingsPreferences.java | 134 ------ src/org/torproject/android/TipsAndTricks.java | 139 ------ src/org/torproject/android/TorConstants.java | 7 +- src/org/torproject/android/TorifiedApp.java | 111 ----- src/org/torproject/android/WizardHelper.java | 425 ------------------ 11 files changed, 37 insertions(+), 1703 deletions(-) delete mode 100644 src/org/torproject/android/AppManager.java delete mode 100644 src/org/torproject/android/ConfigureTransProxy.java delete mode 100644 src/org/torproject/android/LotsaText.java delete mode 100644 src/org/torproject/android/Permissions.java delete mode 100644 src/org/torproject/android/ProcessSettingsAsyncTask.java delete mode 100644 src/org/torproject/android/SettingsPreferences.java delete mode 100644 src/org/torproject/android/TipsAndTricks.java delete mode 100644 src/org/torproject/android/TorifiedApp.java delete mode 100644 src/org/torproject/android/WizardHelper.java diff --git a/src/org/torproject/android/AppManager.java b/src/org/torproject/android/AppManager.java deleted file mode 100644 index 9fbc60c6..00000000 --- a/src/org/torproject/android/AppManager.java +++ /dev/null @@ -1,272 +0,0 @@ -/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */ -/* See LICENSE for licensing information */ - -package org.torproject.android; - -import java.util.Arrays; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.StringTokenizer; - -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.ImageView; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.TextView; - - -public class AppManager extends Activity implements OnCheckedChangeListener, OnClickListener, TorConstants { - - private static TorifiedApp[] apps = null; - - private ListView listApps; - - private AppManager mAppManager; - - - private boolean appsLoaded = false; - - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - this.setContentView(R.layout.layout_apps); - - mAppManager = this; - - - - } - - - - @Override - protected void onResume() { - super.onResume(); - listApps = (ListView)findViewById(R.id.applistview); - - if (!appsLoaded) - loadApps(); - } - - - - private void loadApps () - { - resetApps(this); - final TorifiedApp[] apps = getApps(this); - - Arrays.sort(apps, new Comparator() { - public int compare(TorifiedApp o1, TorifiedApp o2) { - if (o1.isTorified() == o2.isTorified()) return o1.getName().compareTo(o2.getName()); - if (o1.isTorified()) return -1; - return 1; - } - }); - - final LayoutInflater inflater = getLayoutInflater(); - - final ListAdapter adapter = new ArrayAdapter(this,R.layout.layout_apps_item,R.id.itemtext,apps) { - public View getView(int position, View convertView, ViewGroup parent) { - ListEntry entry; - if (convertView == null) { - // Inflate a new view - convertView = inflater.inflate(R.layout.layout_apps_item, parent, false); - entry = new ListEntry(); - entry.icon = (ImageView) convertView.findViewById(R.id.itemicon); - entry.box = (CheckBox) convertView.findViewById(R.id.itemcheck); - entry.text = (TextView) convertView.findViewById(R.id.itemtext); - - entry.text.setOnClickListener(mAppManager); - entry.text.setOnClickListener(mAppManager); - - convertView.setTag(entry); - - entry.box.setOnCheckedChangeListener(mAppManager); - } else { - // Convert an existing view - entry = (ListEntry) convertView.getTag(); - } - - - final TorifiedApp app = apps[position]; - - - entry.icon.setImageDrawable(app.getIcon()); - entry.text.setText(app.getName()); - - final CheckBox box = entry.box; - box.setTag(app); - box.setChecked(app.isTorified()); - - entry.text.setTag(box); - entry.icon.setTag(box); - - return convertView; - } - }; - - listApps.setAdapter(adapter); - - appsLoaded = true; - - } - - private static class ListEntry { - private CheckBox box; - private TextView text; - private ImageView icon; - } - - /* (non-Javadoc) - * @see android.app.Activity#onStop() - */ - @Override - protected void onStop() { - super.onStop(); - - } - - public static TorifiedApp[] getApps (Context context) - { - if (apps == null) - resetApps(context); - - return apps; - } - - public static TorifiedApp[] resetApps (Context context) - { - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - String tordAppString = prefs.getString(PREFS_KEY_TORIFIED, ""); - String[] tordApps; - - StringTokenizer st = new StringTokenizer(tordAppString,"|"); - tordApps = new String[st.countTokens()]; - int tordIdx = 0; - while (st.hasMoreTokens()) - { - tordApps[tordIdx++] = st.nextToken(); - } - - Arrays.sort(tordApps); - - //else load the apps up - PackageManager pMgr = context.getPackageManager(); - - List lAppInfo = pMgr.getInstalledApplications(0); - - Iterator itAppInfo = lAppInfo.iterator(); - - apps = new TorifiedApp[lAppInfo.size()]; - - ApplicationInfo aInfo = null; - - int appIdx = 0; - - while (itAppInfo.hasNext()) - { - aInfo = itAppInfo.next(); - - apps[appIdx] = new TorifiedApp(); - - apps[appIdx].setEnabled(aInfo.enabled); - apps[appIdx].setUid(aInfo.uid); - apps[appIdx].setUsername(pMgr.getNameForUid(apps[appIdx].getUid())); - apps[appIdx].setProcname(aInfo.processName); - apps[appIdx].setName(pMgr.getApplicationLabel(aInfo).toString()); - apps[appIdx].setIcon(pMgr.getApplicationIcon(aInfo)); - - // check if this application is allowed - if (Arrays.binarySearch(tordApps, apps[appIdx].getUsername()) >= 0) { - apps[appIdx].setTorified(true); - } - else - { - apps[appIdx].setTorified(false); - } - - appIdx++; - } - - - return apps; - } - - - public void saveAppSettings (Context context) - { - if (apps == null) - return; - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - - // final SharedPreferences prefs = context.getSharedPreferences(PREFS_KEY, 0); - - StringBuilder tordApps = new StringBuilder(); - - for (int i = 0; i < apps.length; i++) - { - if (apps[i].isTorified()) - { - tordApps.append(apps[i].getUsername()); - tordApps.append("|"); - } - } - - Editor edit = prefs.edit(); - edit.putString(PREFS_KEY_TORIFIED, tordApps.toString()); - edit.commit(); - - } - - - /** - * Called an application is check/unchecked - */ - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - final TorifiedApp app = (TorifiedApp) buttonView.getTag(); - if (app != null) { - app.setTorified(isChecked); - } - - saveAppSettings(this); - - } - - - - @Override - public void onClick(View v) { - - CheckBox cbox = (CheckBox)v.getTag(); - - final TorifiedApp app = (TorifiedApp)cbox.getTag(); - if (app != null) { - app.setTorified(!app.isTorified()); - cbox.setChecked(app.isTorified()); - } - - saveAppSettings(this); - - } - -} diff --git a/src/org/torproject/android/ConfigureTransProxy.java b/src/org/torproject/android/ConfigureTransProxy.java deleted file mode 100644 index d515aaed..00000000 --- a/src/org/torproject/android/ConfigureTransProxy.java +++ /dev/null @@ -1,183 +0,0 @@ -package org.torproject.android; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.net.Uri; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.RadioButton; -import android.widget.RadioGroup; -import android.widget.TextView; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.Toast; - -public class ConfigureTransProxy extends Activity implements TorConstants { - - private Context context; - private int flag = 0; - - protected void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - context = this; - - } - - @Override - protected void onStart() { - - super.onStart(); - setContentView(R.layout.layout_wizard_root); - - stepSix(); - - } - - @Override - protected void onResume() { - super.onResume(); - - - } - - - - private void stepSix(){ - - String title = context.getString(R.string.wizard_transproxy_title); - TextView txtTitle = ((TextView)findViewById(R.id.WizardTextTitle)); - txtTitle.setText(title); - - Button back = ((Button)findViewById(R.id.btnWizard1)); - Button next = ((Button)findViewById(R.id.btnWizard2)); - next.setEnabled(false); - - back.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - - startActivityForResult(new Intent(getBaseContext(), Permissions.class), 1); - } - }); - - next.setOnClickListener(new View.OnClickListener() { - - //Dirty flag variable - improve logic - @Override - public void onClick(View v) { - if( flag == 1 ) - context.startActivity(new Intent(context, AppManager.class)); - - else - showWizardFinal(); - } - }); - - RadioGroup mRadioGroup = (RadioGroup)findViewById(R.id.radioGroup); - mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener (){ - - - @Override - public void onCheckedChanged(RadioGroup group, int checkedId){ - Button next = ((Button)findViewById(R.id.btnWizard2)); - next.setEnabled(true); - next.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - - showWizardFinal(); - } - }); - - RadioButton rb0 = (RadioButton)findViewById(R.id.radio0); - RadioButton rb1 = (RadioButton)findViewById(R.id.radio1); - RadioButton rb2 = (RadioButton)findViewById(R.id.radio2); - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - Editor pEdit = prefs.edit(); - pEdit.putBoolean(PREF_TRANSPARENT, rb0.isChecked()); - pEdit.putBoolean(PREF_TRANSPARENT_ALL, rb0.isChecked()); - pEdit.commit(); - - if(rb0.isChecked()) - { - pEdit.putString("radiobutton","rb0"); - pEdit.commit(); - } - - else if(rb1.isChecked()) - { - flag = 1; - - pEdit.putBoolean(PREF_TRANSPARENT, true); - pEdit.putBoolean(PREF_TRANSPARENT_ALL, false); - pEdit.putString("radiobutton","rb1"); - pEdit.commit(); - - next.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - - context.startActivity(new Intent(context, AppManager.class)); - - - } - }); - } - else if(rb2.isChecked()) - { - pEdit.putString("radiobutton", "rb2"); - pEdit.commit(); - } - - } - }); - - - } - - private void showWizardFinal () - { - String title = null; - String msg = null; - - - title = context.getString(R.string.wizard_final); - msg = context.getString(R.string.wizard_final_msg); - - DialogInterface.OnClickListener ocListener = new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - context.startActivity(new Intent(context, Orbot.class)); - - } - }; - - - new AlertDialog.Builder(context) - .setIcon(R.drawable.icon) - .setTitle(title) - .setPositiveButton(R.string.button_close, ocListener) - .setMessage(msg) - .show(); - - - - - } -} \ No newline at end of file diff --git a/src/org/torproject/android/LotsaText.java b/src/org/torproject/android/LotsaText.java deleted file mode 100644 index 1b0656b6..00000000 --- a/src/org/torproject/android/LotsaText.java +++ /dev/null @@ -1,133 +0,0 @@ -package org.torproject.android; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.view.View; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.TextView; - -public class LotsaText extends Activity implements TorConstants{ - - private Context context; - - protected void onCreate(Bundle savedInstanceState) - { - - - super.onCreate(savedInstanceState); - context = this; - - - } - - @Override - protected void onStart() { - - super.onStart(); - setContentView(R.layout.scrollingtext_buttons_view); - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - boolean wizardScreen1 = prefs.getBoolean("wizardscreen1",true); - if(wizardScreen1) - stepOne(); - else - stepTwo(); - - } - - @Override - protected void onResume() { - super.onResume(); - - - } - - - - private void stepOne() { - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - Editor pEdit = prefs.edit(); - pEdit.putBoolean("wizardscreen1",true); - pEdit.commit(); - - String title = context.getString(R.string.wizard_title); - String msg = context.getString(R.string.wizard_title_msg); - - TextView txtTitle = ((TextView)findViewById(R.id.WizardTextTitle)); - txtTitle.setText(title); - - TextView txtBody = ((TextView)findViewById(R.id.WizardTextBody)); - txtBody.setText(msg); - - Button btn1 = ((Button)findViewById(R.id.btnWizard1)); - Button btn2 = ((Button)findViewById(R.id.btnWizard2)); - ImageView img = (ImageView) findViewById(R.id.orbot_image); - - btn1.setVisibility(Button.INVISIBLE); - img.setImageResource(R.drawable.tor); - - btn2.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - stepTwo(); - } - }); - - } - - private void stepTwo() { - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - Editor pEdit = prefs.edit(); - pEdit.putBoolean("wizardscreen1",false); - pEdit.commit(); - - setContentView(R.layout.scrollingtext_buttons_view); - String title = context.getString(R.string.wizard_warning_title); - String msg = context.getString(R.string.wizard_warning_msg); - - TextView txtTitle = ((TextView)findViewById(R.id.WizardTextTitle)); - txtTitle.setText(title); - - TextView txtBody = ((TextView)findViewById(R.id.WizardTextBody)); - txtBody.setText(msg); - - Button btn1 = ((Button)findViewById(R.id.btnWizard1)); - Button btn2 = ((Button)findViewById(R.id.btnWizard2)); - ImageView img = (ImageView) findViewById(R.id.orbot_image); - - btn1.setVisibility(Button.VISIBLE); - img.setImageResource(R.drawable.warning); - - btn1.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - - stepOne(); - } - }); - - btn2.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - startActivityForResult(new Intent(getBaseContext(), Permissions.class), 1); - } - }); - - } - - -} \ No newline at end of file diff --git a/src/org/torproject/android/Orbot.java b/src/org/torproject/android/Orbot.java index 0f162af7..5470042a 100644 --- a/src/org/torproject/android/Orbot.java +++ b/src/org/torproject/android/Orbot.java @@ -14,6 +14,9 @@ import java.util.StringTokenizer; import org.torproject.android.service.ITorService; import org.torproject.android.service.ITorServiceCallback; import org.torproject.android.service.TorServiceConstants; +import org.torproject.android.settings.ProcessSettingsAsyncTask; +import org.torproject.android.settings.SettingsPreferences; +import org.torproject.android.wizard.LotsaText; import android.app.Activity; import android.app.AlertDialog; @@ -59,7 +62,7 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants private MenuItem mItemOnOff = null; //the menu item which we toggle based on Orbot state /* Some tracking bits */ - private int torStatus = STATUS_READY; //latest status reported from the tor service + private int torStatus = TorServiceConstants.STATUS_OFF; //latest status reported from the tor service // this is a value we get passed back from the TorService /* Tor Service interaction */ @@ -175,7 +178,7 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants { } - else if (mService.getStatus() == STATUS_READY) + else if (mService.getStatus() == TorServiceConstants.STATUS_OFF) { if (mItemOnOff != null) mItemOnOff.setTitle(R.string.menu_stop); @@ -573,7 +576,7 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants if (imgStatus != null) { - if (torStatus == STATUS_ON) + if (torStatus == TorServiceConstants.STATUS_ON) { imgStatus.setImageResource(R.drawable.toron); @@ -584,7 +587,7 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants lblStatus.setText(lblMsg); - if (torServiceMsg.length() > 0) + if (torServiceMsg != null && torServiceMsg.length() > 0) showAlert("Update", torServiceMsg, false); boolean showFirstTime = prefs.getBoolean("connect_first_time",true); @@ -607,7 +610,7 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants } - else if (torStatus == STATUS_CONNECTING) + else if (torStatus == TorServiceConstants.STATUS_CONNECTING) { imgStatus.setImageResource(R.drawable.torstarting); @@ -619,18 +622,6 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants mItemOnOff.setTitle(R.string.menu_stop); } - else if (torStatus == STATUS_OFF) - { - imgStatus.setImageResource(R.drawable.toroff); - - - hideProgressDialog(); - - lblStatus.setText(getString(R.string.status_shutting_down)); - - if (mItemOnOff != null) - mItemOnOff.setTitle(R.string.menu_start); - } else { @@ -704,34 +695,30 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants public boolean onLongClick(View view) { - try + try + { + + if (mService != null && mService.getStatus() == TorServiceConstants.STATUS_OFF) { - if (mService == null) - { - - } - else if (mService.getStatus() == STATUS_READY) - { - - createProgressDialog(getString(R.string.status_starting_up)); + createProgressDialog(getString(R.string.status_starting_up)); - startTor(); - } - else - { - - stopTor(); - - } - + startTor(); } - catch (Exception e) + else { - Log.d(TAG,"error onclick",e); - } - return true; + stopTor(); + + } + + } + catch (Exception e) + { + Log.d(TAG,"error onclick",e); + } + + return true; } @@ -775,13 +762,21 @@ public class Orbot extends Activity implements OnLongClickListener, TorConstants // this is what takes messages or values from the callback threads or other non-mainUI threads //and passes them back into the main UI thread for display to the user private Handler mHandler = new Handler() { + + private String lastServiceMsg = null; + public void handleMessage(Message msg) { switch (msg.what) { case TorServiceConstants.STATUS_MSG: String torServiceMsg = (String)msg.getData().getString(HANDLER_TOR_MSG); - updateStatus(torServiceMsg); + if (lastServiceMsg == null || !lastServiceMsg.equals(torServiceMsg)) + { + updateStatus(torServiceMsg); + + lastServiceMsg = torServiceMsg; + } break; case TorServiceConstants.LOG_MSG: diff --git a/src/org/torproject/android/Permissions.java b/src/org/torproject/android/Permissions.java deleted file mode 100644 index 2ee4f7e3..00000000 --- a/src/org/torproject/android/Permissions.java +++ /dev/null @@ -1,229 +0,0 @@ -package org.torproject.android; - -import org.torproject.android.service.TorService; -import org.torproject.android.service.TorServiceUtils; -import org.torproject.android.service.TorTransProxy; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.util.Log; -import android.view.View; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.TextView; -import android.widget.Toast; - -public class Permissions extends Activity implements TorConstants { - - private Context context; - - protected void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - context = this; - - } - - @Override - protected void onStart() { - - super.onStart(); - setContentView(R.layout.layout_wizard_permissions); - - stepThree(); - - } - - @Override - protected void onResume() { - super.onResume(); - - - } - - private void stepThree(){ - - boolean hasRoot = TorServiceUtils.checkRootAccess(); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - Editor pEdit = prefs.edit(); - pEdit.putBoolean("has_root",hasRoot); - pEdit.commit(); - - if (hasRoot) - { - stepFourRoot(); - } - else - { - stepFour(); - } - - } - - private void stepFourRoot(){ - - String title = context.getString(R.string.wizard_permissions_title); - String msg1 = context.getString(R.string.wizard_permissions_root_msg1); - String msg2 = context.getString(R.string.wizard_permissions_root_msg2); - - TextView txtTitle = ((TextView)findViewById(R.id.WizardTextTitle)); - txtTitle.setText(title); - - TextView txtBody1 = ((TextView)findViewById(R.id.WizardTextBody1)); - txtBody1.setText(msg1); - - - TextView txtBody2 = ((TextView)findViewById(R.id.WizardTextBody2)); - txtBody2.setText(msg2); - txtBody2.setVisibility(TextView.VISIBLE); - - Button grantPermissions = ((Button)findViewById(R.id.grantPermissions)); - grantPermissions.setVisibility(Button.VISIBLE); - - Button back = ((Button)findViewById(R.id.btnWizard1)); - Button next = ((Button)findViewById(R.id.btnWizard2)); - next.setEnabled(false); - - CheckBox consent = (CheckBox)findViewById(R.id.checkBox); - consent.setVisibility(CheckBox.VISIBLE); - - consent.setOnCheckedChangeListener(new OnCheckedChangeListener (){ - - @Override - public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { - - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - Editor pEdit = prefs.edit(); - - pEdit.putBoolean(PREF_TRANSPARENT, !isChecked); - pEdit.putBoolean(PREF_TRANSPARENT_ALL, !isChecked); - - pEdit.commit(); - - Button next = ((Button)findViewById(R.id.btnWizard2)); - if(isChecked) - next.setEnabled(true); - else - next.setEnabled(false); - - - } - - }); - - - grantPermissions.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - //Check and Install iptables - TorTransProxy.testOwnerModule(this) - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean hasRoot = prefs.getBoolean("has_root",false); - - if (hasRoot) - { - try { - int resp = TorTransProxy.testOwnerModule(context); - - if (resp < 0) - { - hasRoot = false; - Toast.makeText(context, "ERROR: IPTables OWNER module not available", Toast.LENGTH_LONG).show(); - - Log.i(TorService.TAG,"ERROR: IPTables OWNER module not available"); - stepFour(); - } - - } catch (Exception e) { - - hasRoot = false; - Log.d(TorService.TAG,"ERROR: IPTables OWNER module not available",e); - } - } - - startActivityForResult(new Intent(getBaseContext(), ConfigureTransProxy.class), 1); - - - } - }); - - back.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - - startActivityForResult(new Intent(getBaseContext(), LotsaText.class), 1); - } - }); - - - next.setOnClickListener(new View.OnClickListener() { - - - @Override - public void onClick(View v) { - startActivityForResult(new Intent(getBaseContext(), TipsAndTricks.class), 1); - } - }); - - } - - private void stepFour(){ - - Toast.makeText(context, "NON ROOT FUNC", Toast.LENGTH_SHORT).show(); - String title = context.getString(R.string.wizard_permissions_title); - String msg = context.getString(R.string.wizard_permissions_msg); - - TextView txtTitle = ((TextView)findViewById(R.id.WizardTextTitle)); - txtTitle.setText(title); - - TextView txtBody = ((TextView)findViewById(R.id.WizardTextBody1)); - txtBody.setText(msg); - - Button btn1 = ((Button)findViewById(R.id.btnWizard1)); - Button btn2 = ((Button)findViewById(R.id.btnWizard2)); - btn2.setEnabled(true); - - - TextView txtBody2 = ((TextView)findViewById(R.id.WizardTextBody2)); - txtBody2.setVisibility(TextView.GONE); - - Button grantPermissions = ((Button)findViewById(R.id.grantPermissions)); - grantPermissions.setVisibility(Button.GONE); - - - CheckBox consent = (CheckBox)findViewById(R.id.checkBox); - consent.setVisibility(CheckBox.GONE); - - btn1.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - - startActivityForResult(new Intent(getBaseContext(), LotsaText.class), 1); - } - }); - - btn2.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - startActivityForResult(new Intent(getBaseContext(), TipsAndTricks.class), 1); - } - }); - } - - -} \ No newline at end of file diff --git a/src/org/torproject/android/ProcessSettingsAsyncTask.java b/src/org/torproject/android/ProcessSettingsAsyncTask.java deleted file mode 100644 index c4e88a7e..00000000 --- a/src/org/torproject/android/ProcessSettingsAsyncTask.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.torproject.android; - -import org.torproject.android.service.ITorService; - -import android.os.AsyncTask; -import android.os.RemoteException; - -public class ProcessSettingsAsyncTask extends AsyncTask -{ - - - @Override - protected Long doInBackground(ITorService... torService) { - - try { - torService[0].processSettings(); - } catch (RemoteException e) { - e.printStackTrace(); - } - - return 100L; - } - - protected void onProgressUpdate(Integer... progress) { - - } - - protected void onPostExecute(Long result) { - - } - -} diff --git a/src/org/torproject/android/SettingsPreferences.java b/src/org/torproject/android/SettingsPreferences.java deleted file mode 100644 index 7cf90936..00000000 --- a/src/org/torproject/android/SettingsPreferences.java +++ /dev/null @@ -1,134 +0,0 @@ -/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */ -/* See LICENSE for licensing information */ - -package org.torproject.android; - -import org.torproject.android.service.TorServiceUtils; -import org.torproject.android.service.TorTransProxy; - -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.Preference; -import android.preference.PreferenceManager; -import android.preference.Preference.OnPreferenceClickListener; -import android.preference.PreferenceActivity; -import android.preference.PreferenceCategory; - - -public class SettingsPreferences - extends PreferenceActivity implements OnPreferenceClickListener { - - private CheckBoxPreference prefCBTransProxy = null; - private CheckBoxPreference prefcBTransProxyAll = null; - private Preference prefTransProxyApps = null; - private CheckBoxPreference prefHiddenServices = null; - - private boolean hasRoot = false; - - - private final static int HIDDEN_SERVICE_PREF_IDX = 6; - - protected void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.preferences); - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - - if (prefs.contains("has_root")) - { - hasRoot = prefs.getBoolean("has_root",false); - } - else - { - hasRoot = TorServiceUtils.checkRootAccess(); - Editor pEdit = prefs.edit(); - pEdit.putBoolean("has_root",hasRoot); - pEdit.commit(); - } - } - - - @Override - protected void onResume() { - - super.onResume(); - - - int transProxyGroupIdx = 1; - - if (!hasRoot) - { - getPreferenceScreen().getPreference(transProxyGroupIdx).setEnabled(false); - } - else - { - prefCBTransProxy = ((CheckBoxPreference)((PreferenceCategory)this.getPreferenceScreen().getPreference(transProxyGroupIdx)).getPreference(0)); - prefcBTransProxyAll = (CheckBoxPreference)((PreferenceCategory)this.getPreferenceScreen().getPreference(transProxyGroupIdx)).getPreference(1); - prefTransProxyApps = ((PreferenceCategory)this.getPreferenceScreen().getPreference(transProxyGroupIdx)).getPreference(2); - - prefcBTransProxyAll.setEnabled(prefCBTransProxy.isChecked()); - - prefTransProxyApps.setEnabled(prefCBTransProxy.isChecked() && (!prefcBTransProxyAll.isChecked())); - - prefCBTransProxy.setOnPreferenceClickListener(this); - prefcBTransProxyAll.setOnPreferenceClickListener(this); - prefTransProxyApps.setOnPreferenceClickListener(this); - - } - - - prefHiddenServices = ((CheckBoxPreference)((PreferenceCategory)this.getPreferenceScreen().getPreference(HIDDEN_SERVICE_PREF_IDX)).getPreference(0)); - prefHiddenServices.setOnPreferenceClickListener(this); - ((PreferenceCategory)this.getPreferenceScreen().getPreference(HIDDEN_SERVICE_PREF_IDX)).getPreference(1).setEnabled(prefHiddenServices.isChecked()); - ((PreferenceCategory)this.getPreferenceScreen().getPreference(HIDDEN_SERVICE_PREF_IDX)).getPreference(2).setEnabled(prefHiddenServices.isChecked()); - - - }; - - - - - /* (non-Javadoc) - * @see android.app.Activity#onStop() - */ - @Override - protected void onStop() { - super.onStop(); - - //Log.d(getClass().getName(),"Exiting Preferences"); - } - - @Override - public boolean onPreferenceClick(Preference preference) { - - setResult(1010); - - if (preference == prefTransProxyApps) - { - startActivity(new Intent(this, AppManager.class)); - - } - else if (preference == prefHiddenServices) - { - - ((PreferenceCategory)this.getPreferenceScreen().getPreference(HIDDEN_SERVICE_PREF_IDX)).getPreference(1).setEnabled(prefHiddenServices.isChecked()); - ((PreferenceCategory)this.getPreferenceScreen().getPreference(HIDDEN_SERVICE_PREF_IDX)).getPreference(2).setEnabled(prefHiddenServices.isChecked()); - - } - else - { - prefcBTransProxyAll.setEnabled(prefCBTransProxy.isChecked()); - prefTransProxyApps.setEnabled(prefCBTransProxy.isChecked() && (!prefcBTransProxyAll.isChecked())); - - } - - return true; - } - - - -} diff --git a/src/org/torproject/android/TipsAndTricks.java b/src/org/torproject/android/TipsAndTricks.java deleted file mode 100644 index ebb5ad37..00000000 --- a/src/org/torproject/android/TipsAndTricks.java +++ /dev/null @@ -1,139 +0,0 @@ -package org.torproject.android; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.TextView; - -public class TipsAndTricks extends Activity implements TorConstants { - - private Context context; - - protected void onCreate(Bundle savedInstanceState) - { - super.onCreate(savedInstanceState); - context = this; - - } - - @Override - protected void onStart() { - - super.onStart(); - setContentView(R.layout.layout_wizard_tips); - - stepFive(); - - } - - @Override - protected void onResume() { - super.onResume(); - - - } - - void stepFive(){ - - String title = context.getString(R.string.wizard_tips_title); - TextView txtTitle = ((TextView)findViewById(R.id.WizardTextTitle)); - txtTitle.setText(title); - - Button btn1 = (Button)findViewById(R.id.WizardRootButtonInstallGibberbot); - - btn1.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View view) { - - String url = context.getString(R.string.gibberbot_apk_url); - context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); - - } - }); - - Button btn2 = (Button)findViewById(R.id.WizardRootButtonInstallFirefox); - - btn2.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View view) { - - String url = context.getString(R.string.firefox_apk_url); - context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); - - } - }); - - Button btn3 = (Button)findViewById(R.id.WizardRootButtonInstallProxyMob); - - btn3.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View view) { - - String url = context.getString(R.string.proxymob_url); - context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); - } - }); - - Button back = ((Button)findViewById(R.id.btnWizard1)); - Button next = ((Button)findViewById(R.id.btnWizard2)); - - back.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - - startActivityForResult(new Intent(getBaseContext(), Permissions.class), 1); - } - }); - - next.setOnClickListener(new View.OnClickListener() { - - @Override - public void onClick(View v) { - showWizardFinal(); - } - }); - - } - - private void showWizardFinal () - { - String title = null; - String msg = null; - - - title = context.getString(R.string.wizard_final); - msg = context.getString(R.string.wizard_final_msg); - - DialogInterface.OnClickListener ocListener = new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - context.startActivity(new Intent(context, Orbot.class)); - - } - }; - - - new AlertDialog.Builder(context) - .setIcon(R.drawable.icon) - .setTitle(title) - .setPositiveButton(R.string.button_close, ocListener) - .setMessage(msg) - .show(); - - - - - } -} \ No newline at end of file diff --git a/src/org/torproject/android/TorConstants.java b/src/org/torproject/android/TorConstants.java index 56eb5d52..38bb0d2d 100644 --- a/src/org/torproject/android/TorConstants.java +++ b/src/org/torproject/android/TorConstants.java @@ -16,11 +16,6 @@ public interface TorConstants { //path to check Tor against public final static String URL_TOR_CHECK = "https://check.torproject.org"; - public final static int STATUS_OFF = -1; - public final static int STATUS_READY = 0; - public final static int STATUS_ON = 1; - public final static int STATUS_CONNECTING = 2; - public final static String NEWLINE = "\n"; @@ -45,6 +40,8 @@ public interface TorConstants { public final static String PREF_TRANSPARENT = "pref_transparent"; public final static String PREF_TRANSPARENT_ALL = "pref_transparent_all"; + public final static String PREF_HAS_ROOT = "has_root"; + } diff --git a/src/org/torproject/android/TorifiedApp.java b/src/org/torproject/android/TorifiedApp.java deleted file mode 100644 index 9e659e75..00000000 --- a/src/org/torproject/android/TorifiedApp.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.torproject.android; - -import android.graphics.drawable.Drawable; - -public class TorifiedApp { - - private boolean enabled; - private int uid; - private String username; - private String procname; - private String name; - private Drawable icon; - - private boolean torified = false; - - /** - * @return the torified - */ - public boolean isTorified() { - return torified; - } - /** - * @param torified the torified to set - */ - public void setTorified(boolean torified) { - this.torified = torified; - } - private int[] enabledPorts; - - /** - * @return the enabledPorts - */ - public int[] getEnabledPorts() { - return enabledPorts; - } - /** - * @param enabledPorts the enabledPorts to set - */ - public void setEnabledPorts(int[] enabledPorts) { - this.enabledPorts = enabledPorts; - } - /** - * @return the enabled - */ - public boolean isEnabled() { - return enabled; - } - /** - * @param enabled the enabled to set - */ - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - /** - * @return the uid - */ - public int getUid() { - return uid; - } - /** - * @param uid the uid to set - */ - public void setUid(int uid) { - this.uid = uid; - } - /** - * @return the username - */ - public String getUsername() { - return username; - } - /** - * @param username the username to set - */ - public void setUsername(String username) { - this.username = username; - } - /** - * @return the procname - */ - public String getProcname() { - return procname; - } - /** - * @param procname the procname to set - */ - public void setProcname(String procname) { - this.procname = procname; - } - /** - * @return the name - */ - public String getName() { - return name; - } - /** - * @param name the name to set - */ - public void setName(String name) { - this.name = name; - } - - - public Drawable getIcon() { - return icon; - } - - public void setIcon(Drawable icon) { - this.icon = icon; - } -} diff --git a/src/org/torproject/android/WizardHelper.java b/src/org/torproject/android/WizardHelper.java deleted file mode 100644 index c85c50a0..00000000 --- a/src/org/torproject/android/WizardHelper.java +++ /dev/null @@ -1,425 +0,0 @@ -package org.torproject.android; - -import org.torproject.android.service.TorService; -import org.torproject.android.service.TorServiceUtils; -import org.torproject.android.service.TorTransProxy; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.SharedPreferences.Editor; -import android.net.Uri; -import android.preference.PreferenceManager; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.TextView; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.Toast; - -public class WizardHelper implements TorConstants { - - private Context context; - private AlertDialog currentDialog; - - public WizardHelper (Context context) - { - this.context = context; - } - - - public void showWizard () - { - showWizardStep1(); - } - - public void showWizardStep1() - { - - - String title = context.getString(R.string.wizard_title); - - LayoutInflater li = LayoutInflater.from(context); - View view = li.inflate(R.layout.layout_wizard_welcome, null); - - - showCustomDialog(title, view,context.getString(R.string.btn_next),null,new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - - if (which == DialogInterface.BUTTON_NEUTRAL) - { - - showWizardStep2(); - } - /* - else if (which == DialogInterface.BUTTON_POSITIVE) - { - showAbout(); - }*/ - - } - }); - } - - public void showWizardStep2() - { - - - String title = context.getString(R.string.wizard_permissions_stock); - - LayoutInflater li = LayoutInflater.from(context); - View view = li.inflate(R.layout.layout_wizard_stock, null); - - Button btn1 = (Button)view.findViewById(R.id.WizardRootButtonEnable); - - btn1.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View view) { - - - boolean hasRoot = TorServiceUtils.checkRootAccess(); - - if (hasRoot) - { - try { - int resp = TorTransProxy.testOwnerModule(context); - - if (resp < 0) - { - hasRoot = false; - Toast.makeText(context, "ERROR: IPTables OWNER module not available", Toast.LENGTH_LONG).show(); - - Log.i(TorService.TAG,"ERROR: IPTables OWNER module not available"); - } - - } catch (Exception e) { - - hasRoot = false; - Log.d(TorService.TAG,"ERROR: IPTables OWNER module not available",e); - } - } - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - Editor pEdit = prefs.edit(); - pEdit.putBoolean("has_root",hasRoot); - pEdit.commit(); - - if (hasRoot) - { - currentDialog.dismiss(); - showWizardStep2Root(); - } - else - { - Toast.makeText(context, "Unable to get root access", Toast.LENGTH_LONG).show(); - view.setEnabled(false); - } - } - }); - - CheckBox cb1 = (CheckBox)view.findViewById(R.id.CheckBoxConsent); - - cb1.setOnCheckedChangeListener(new OnCheckedChangeListener (){ - - @Override - public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { - - currentDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setEnabled(isChecked); - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - Editor pEdit = prefs.edit(); - pEdit.putBoolean("has_root",false); - pEdit.commit(); - - } - - }); - - - showCustomDialog(title, view,context.getString(R.string.btn_next),context.getString(R.string.btn_back),new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - - if (which == DialogInterface.BUTTON_NEUTRAL) - { - showWizardTipsAndTricks(); - } - else if (which == DialogInterface.BUTTON_POSITIVE) - { - showWizardStep1(); - } - - } - }); - - currentDialog.getButton(AlertDialog.BUTTON_NEUTRAL).setEnabled(false); - - - } - - public void showWizardStep2Root() - { - - String title = null; - String msg = null; - - - - title = context.getString(R.string.wizard_permissions_root); - msg = context.getString(R.string.wizard_premissions_msg_root); - - - - showDialog(title, msg,context.getString(R.string.btn_next),context.getString(R.string.btn_back),new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - - if (which == DialogInterface.BUTTON_NEUTRAL) - { - showWizardRootConfigureTorification(); - } - else if (which == DialogInterface.BUTTON_POSITIVE) - { - showWizardStep1(); - } - - } - }); - - - } - - public void showWizardTipsAndTricks() - { - - String title = context.getString(R.string.wizard_tips_tricks); - - LayoutInflater li = LayoutInflater.from(context); - View view = li.inflate(R.layout.layout_wizard_tips, null); - - Button btn1 = (Button)view.findViewById(R.id.WizardRootButtonInstallGibberbot); - - btn1.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View view) { - - String url = context.getString(R.string.otrchat_apk_url); - context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); - - } - }); - - Button btn2 = (Button)view.findViewById(R.id.WizardRootButtonInstallFirefox); - - btn2.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View view) { - - String url = context.getString(R.string.orweb_apk_url); - context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); - - } - }); - - Button btn3 = (Button)view.findViewById(R.id.WizardRootButtonInstallProxyMob); - - btn3.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View view) { - - showProxyHelp(); - - } - }); - - showCustomDialog(title, view,context.getString(R.string.btn_next),context.getString(R.string.btn_back),new DialogInterface.OnClickListener() { - - - - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - - if (which == DialogInterface.BUTTON_NEUTRAL) - { - showWizardFinal(); - - } - else if (which == DialogInterface.BUTTON_POSITIVE) - { - showWizardStep2(); - } - - } - }); - } - - public void showWizardRootConfigureTorification() - { - /* - LayoutInflater li = LayoutInflater.from(context); - View view = li.inflate(R.layout.layout_wizard_root, null); - - CheckBox cb1 = (CheckBox)view.findViewById(R.id.WizardRootCheckBox01); - Button btn1 = (Button)view.findViewById(R.id.WizardRootButton01); - - cb1.setOnCheckedChangeListener(new OnCheckedChangeListener (){ - - @Override - public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { - - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - Editor pEdit = prefs.edit(); - - pEdit.putBoolean(PREF_TRANSPARENT, isChecked); - pEdit.putBoolean(PREF_TRANSPARENT_ALL, isChecked); - - pEdit.commit(); - - //Button btn1 = (Button)buttonView.getParent().findViewById(R.id.WizardRootButton01); - //btn1.setEnabled(!isChecked); - - } - - }); - - - - btn1.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View view) { - - - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - - Editor pEdit = prefs.edit(); - pEdit.putBoolean(PREF_TRANSPARENT, true); - pEdit.putBoolean(PREF_TRANSPARENT_ALL, false); - pEdit.commit(); - - context.startActivity(new Intent(context, AppManager.class)); - - } - }); - - showCustomDialog(context.getString(R.string.wizard_configure),view,context.getString(R.string.btn_next),context.getString(R.string.btn_back),new DialogInterface.OnClickListener() { - - @Override - public void onClick(DialogInterface dialog, int which) { - - dialog.dismiss(); - - if (which == DialogInterface.BUTTON_NEUTRAL) - { - showWizardTipsAndTricks(); - - } - else if (which == DialogInterface.BUTTON_POSITIVE) - { - showWizardStep2(); - } - - } - }); - - */ - - } - - - private void showWizardFinal () - { - String title = null; - String msg = null; - - - title = context.getString(R.string.wizard_final); - msg = context.getString(R.string.wizard_final_msg); - - new AlertDialog.Builder(context) - .setIcon(R.drawable.icon) - .setTitle(title) - .setPositiveButton(R.string.button_close, null) - .setMessage(msg) - .show(); - - - - - - } - - public void showDialog (String title, String msg, String button1, String button2, DialogInterface.OnClickListener ocListener) - { - -// dialog.setContentView(R.layout.custom_dialog); - - - AlertDialog.Builder builder = new AlertDialog.Builder(context) - .setIcon(R.drawable.icon) - .setTitle(title) - .setMessage(msg) - .setNeutralButton(button1, ocListener) - .setPositiveButton(button2, ocListener); - - - currentDialog = builder.show(); - - - } - - private void showCustomDialog (String title, View view, String button1, String button2, DialogInterface.OnClickListener ocListener) - { - - currentDialog = new AlertDialog.Builder(context) - .setIcon(R.drawable.icon) - .setTitle(title) - .setView(view) - .setNeutralButton(button1, ocListener) - .setPositiveButton(button2, ocListener) - .show(); - - - } - - - - private void showProxyHelp () - { - - LayoutInflater li = LayoutInflater.from(context); - View view = li.inflate(R.layout.layout_wizard_proxy_help, null); - - new AlertDialog.Builder(context) - .setTitle(context.getString(R.string.wizard_proxy_help_info)) - .setView(view) - .show(); - } - -} - From def974fa958c44d930047fb48122f472d4fe0301 Mon Sep 17 00:00:00 2001 From: Nathan Freitas Date: Fri, 28 Oct 2011 00:31:26 -0400 Subject: [PATCH 03/19] updated layout, strings, and graphics --- res/drawable/ic_launcher_gibberbot.png | Bin 7527 -> 6365 bytes res/drawable/tor.png | Bin 6682 -> 4766 bytes res/drawable/warning.png | Bin 2922 -> 2735 bytes res/layout/layout_wizard_permissions.xml | 39 ++++++++---- res/layout/layout_wizard_tips.xml | 37 ++++++++---- res/layout/scrollingtext_buttons_view.xml | 18 +++--- res/values-ar/strings.xml | 5 -- res/values-ca/strings.xml | 4 -- res/values-de/strings.xml | 4 -- res/values-es/strings.xml | 4 -- res/values-fa/strings.xml | 4 -- res/values-mk/strings.xml | 4 -- res/values-nb/strings.xml | 4 -- res/values-nl/strings.xml | 4 -- res/values-pl/strings.xml | 5 -- res/values-pt/strings.xml | 4 -- res/values-ru/strings.xml | 4 -- res/values-sv/strings.xml | 4 -- res/values-zh/strings.xml | 4 -- res/values/strings.xml | 69 ++++++++++++++-------- res/xml/preferences.xml | 26 ++++++++ 21 files changed, 129 insertions(+), 114 deletions(-) diff --git a/res/drawable/ic_launcher_gibberbot.png b/res/drawable/ic_launcher_gibberbot.png index e4099106985fefd8e0bd2a0d83634e90052a3b07..24835a265e3e9629c704f9fe4730293997c040db 100644 GIT binary patch literal 6365 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 literal 7527 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

FsV;ci zgDg&>;ZH@x`xY~7FfYmk;NKQQj=s+=)Voh129`!0X+mZW8ut{zu%P<##MxLTSTA?M z^+B4w^2OteT0LczM_l2z`@t?B3Er&r<^Z%6D~c7uYm(~My37qvUz>SFbI!0UpC3|( z)kl^yg7Xu|r4^9jd7d&!QUU1+=YAW*(aFZIRxTDE950@qpGSdPJQ>FY*v8gaZfg)Y zD>;5y^$NXY*9$!ytj4fI9ebh`0=}y%JQ+5D-ipF@741f^Ws|CjBBM9}jK3bbQormR z=2SQxx~}#T?-J%@_DqZm$Zwz=pW|vui~CUAii6CCUBl4pwMRoL?ZK-fiA;O+4pyB6 znpcyz*=YP9)5UcTw(MU`!oJ&|zyH9M`*6h|J=SC49cMDPO2*Hxz}3HQ?U)FDpjU3$ z)-+uekNj5GLE0286cKU?yEBWSRvMvI^R`?Gp&}2zM_6}MKD9-Z(3W*wVgK9r^OFo->Zyqd z);&*8u|sQfz!!n=nlB%>IL|iqb0o4|T7=y)qn_u16}lgCe#=sqJLW!pxK$g=6&hp( zVR@txOVwS2`~c!e_O?m;`Lr0}6p_x!m$UuM@MY&pfSE#0wAJnw?cV4Jp=!_5{=x;E zyW}(Fo>OU{ab_w8sNcv*V`!_4!KOu#d2!yY(iB-s zfls~;n|~n~qbi7r&ri7*#f63a_0ry$Q@=jB@4HoYHIxfG+_w^|(Iw>KI65aM z2RW6*<;QKelL~lkQ*WU%WB#6Puk@>tO9E4XiS&|S)%No$PGpvzEtb}})^6lYGN;P0 z)zOqi4)VK(AH&ugU1#G*_^7XAX>$e!p$vsA5WR=bt5_!jC+`PRzIxqK;jt1!*#@dE zM{5&QBHVb~)ywkmUl+Pgey{gTMebOYcBh~xhpITF$BSZg964#?Jl}2Ht!_uWslohY zn;Wxoxx5Ybu!(obw2zzO$(vw@c_>EuIxHup6V1u_t#_JC*_yS!sG z4Hc-$4`@8iQ}o#kGJLisLRo7zKzr8~WBha=%PHzTSp>oG8qd1>`)U6)L4~+As>vKF zsz`o2pV>X*2Y8kGuN?Vb3j(DpUabGV!Y48pv$rFU55ij?%&sH0*iAh9W#Z_fxu6`M z>@d?3_Ue@TmoLR5!l%n5_<5iH65&ZrAb39zeYwrsI4?f0v;dHGMcPV)tRi@~mlbos=z!H?=@PyE`4A3wBj-H;UAFR_Jm7l|spy82uo^x`~9j8;tW}2Hfth(uA|n2{SN+E&~SeEvvVvKYRw>UdndF zdn1OZe&Zms6gM`0tB~gU5fDqaCPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2ipf4 z0{|nLh~kU@01_TaL_t(|+U;6tlvUN0{?56>o2y>U0~A9679gXDh2TWM#6W;34hy3l zjfy70w1}-SF-DC>OuCIj69d5jfrf5H#a5!lq$u+sP%;!%Of}ELo8P_noU{AKD@^)V zvf82$o4wXsZ@u^9-m|~+?Qie1_W}N&8~ds+kcc>AOs!b4A}=0~50X+InmToAeCW`j z)DzF=UuEZytXrY8+gGqdJ2qZ!+3mmk?7%M1ym|9tB^B$icS{BP+S9XsHl?rL{>J>1 zhc?x(TJp!)XaAppQrCk|e6Qd_VDLX|58d{H{@DD-^A7JK4glMae0WLY(Ur@$mM^DO z8y7zV0FU4Y>0R57&iv??@4PtqyQTN_#C!Gg?fC5V5AZ?wl*!`<#>G$N1xHL^WxrlT zSG$7G{k9^B(z0!r&0jco+N))Ie>bOpR{z<`rOggb%KXDePwy`KS^)5CPVD&cGFLFz za^vzF=RLboYrMK+^y5pxW0x5JG4sw@|E$vZIUh zU3Ci~jQ!4V-^&UA_6hSR+&6MrZ4>dLe5QJ83FnOgFLqXPFwk>Lm(M)oWmoJCZ~f81 z^s=$pX(jSt{Ri3`+r9%S8|*9l{Acpa4)wDM_l;ck$(Eh`-L=1=o?HhzfAj}q47BKz zU+o!DIC%V_gMWh38&q2EFkXIS2Nf3O(b$q{k<%N#_w%{;4_~zKmHk}Vm(kB2VHZ9C zL{Biro~6x)R*!6wWrt*22OT-Sodxs9vf9RzDks;?hh1`S^w8F0KY4!s>&tGwcPC%_ zW(^^98};;B&Px`k#j^l_6QR(fUF~IvG~`oPD4$ze9dXU!rGeXG^+#@)`~3Vz*1URC z6Mt~cFB;H~foMJX!)+fV}@QA8IU#luKVsBv1Y?h z%J{Ke;dADEuQOojoY(cMCl5f$+$qB5?@zR+ zLBw^|b87#U0N~y=_Xvzj>CSWE@Ksf9@3~`Lh1~72VFnnVsP2D%;}vt35#7UBFF4;L zA<#NJxR=W$gpr(bzfMbWUx6E8cgvjWLp z+mtU2Ko0x+X=%ex%9!c$+TMVEJ((>VjxOHvdh^l!{Um2fGoxzK)WMOlDDHTiSDq2Jv%V{CytS%lM-joOj_x~Zn$m9K35 z=bPsHmp-|XdNVAw-gwE%-K!`b?BIW1b0F3yKWox;)BE)uIcBuVbro`_V=$$uVqds5 za@Bi#wjKuBYTL45GFVgQQVLkT$1+|}H)@zjwPKnE)v;G?#(VfF*s zyX&451~!&v80Bu2F0f zF5|DY{Xvc^ntk;ZgT}sn<2NP+viqi2F|fF8E6NO-RDY%wQ?9;BT|4@kiO>Fi(c+D3 z?imU=L_`d@gI$mS3?4e0!z!n3wBH0U<8)i&x=FK(GVl18>nNFUij|VyL_)AWCF!uj zjm+ouv8mIpQB|kvr#$x3i+_IlpO?*Kj1jPkCKZlj7YqQG`^Pf?>_o*|3f|j>GRBsE z^V(}x{o>cNGM|5Lj!ak%mqHoXw`8+JpFO1Wl*RpYA2J-vvo}q^17G1tJm_kr1}a6lGI z#BD}IU<80O?Avt^1qIn4PN>)#hu<><9=`^Wl(c>Cc5K?Zjcq&p!M=xPy|nPfb@Sf( zN*6*u%zi-I*Sb)xe6u`r^3>~Bjv1Wu=!(}L&z|%B8@StNFxwW4btA5X0@F3r*EPdq zxS{)WFlM3lNE~jD7go|@MTJFd)Xi+u0*qzFG|U zebFNRquL)Ucy7%=qG9{g$?3yZu3R9pa?^P<8t0txzrKwCWlLxt1G~0=hM?|4pvVW| zNbLVh8+5B50vRq?Ne2MI)Lpc9?*X}Z&7XDCA6Pu)vTrR|^~t9eXp8ttFyI&Yzv7QI zJfcd+J(OEtSH5fNl)fb!KK!L^dJH`pO>j-)U#N{zK&Unh)8_)?3@z<#(Bcf-tHI?l zk%-38cq$2x+XE#Pge{OrBw62rKCEQG5Ottx%lPu@UG7W!7H=CkGN@{6>eYD_!JJ|1 z*{_;@p}sf%iGI8HZ`}6Hse=Y@-1wwO2w}!!Nv3fQ1_q`vSYZb($68_f4444}L6ICN8k5DM+pA%q$t z$STf6punHf0LI|N9i-*^5s%vlw?vVd>j%sPx;mq9ED76^a4ZSoNOXn5ydXE1-+I-( zB9X8kUi9Y6^MI`??C#IbO9&k9vKi4Scj*mx|Gv0HPFefr^Ab9AD`|sq2DjHlYeNVv zXFA{uxRF(y0o|oR+7f3+TD3Ke2xbOg1`O0!b|9}f1MRIHXgnq0^Lk<10!k>4DlnaV4`mU+rxTI1N=Z@Vo#0>01kyy!N0ubYzhh z>!!WO>%z%n&1h)|p?G*6yqR8*QXrKY27Cd)iF%}G1)#fhL^@*t|NiAtjrA9 zwty50N=OKyAccf&TdXLzKb@*O?X798A5hzRaOMBi`7f;jFRc36w7YIE4PJTGa4i~5 zId2#`&Qvv{xuFvy#`lBfGC)!Rl*$0$4Ct0FJ0Tz~2_ix;$B*{W`U>XAnLZ~SM#tEk1K)f{$t}%E5E;v#^hXG5AA{I|V zItq>>;W!euEmMqe2=RCl*@0X&G<$T$sSTe#1_0Fl5cMhmtCw#ox#sdILndB1nxrE@ z1aQt#akvH}#teYlZ9*yeh4WnFa1sJd$J=1~OaL6-Y%gM+7OaR3x7UE-N{MD5JBC;^ z1|bQyE#TM^!jce{f@4cqmVmOQR-D`4IMjadY9cawH3W#r$j#22SX`3s&&dlyNC~&w z#F>*#&^Sk7-z+388vq0242*NM)pnt&svS9lGT_hkLMa7ELgwIfR3C1J;nKmt5baDL zy}t{ga12r?IF^F2Q!H@o)JHlBws0uJn=OiiS$*#R*1ul`08dSSnVoY07XI6t+JiYZ3t)N;2upx-4kzIt zJ=+K994!rDWaRlknu5pcLNpwQuoWEJfn#+$?}(HZI0{Kiz@vN6(h;F08=e9HJhgt= zxo5z~dp2YF8*j5{eY0NRPXmFG%Wb0iR1<<3e)#-uIF5j>YmiD}$Ce7@VWAo5Dq2b@@R;6IuK5Z^3K^T;3x=3LP!PaNGJsa-EIKw z-SL0$+yfBYT!rK1%`l`*ndt@y1jEqL+S-W$1M^^80-Q6LrjFfPkD<7v0DT8#!%EsX z+c?uq4R+K<`>8HSrQl2VfS5!gVuKL_=c%0+j_P(?e&P7v{+5EEb9e8S!X2g4F>Gvq zX1e`67Lx!0LhcrYIzUSZe~B zi^FZ2h{lpIObtQ_2oQuw)d8s*K&3*$QE-HWBNS{$At~kA1lv0RywG4x`Qed1T5f|uai^4Q@*p5JFM;Ju|^WZosMgRck04c(W!wvA~`H)$hj+XW?bd4h| z&y7Sp0V^S3B`t7p2uDHMDisQjge|)30Xr26j$LMYn5eC3g4<;x)DZzA29MVS{mtGmjiau*6-K&_K!yi_EDzf2VsLB; zfT5*1jAYz`9kaoh4%-&6Ww+x_O8upyAf$p)#3G599`gXefD{U$t|;>JGawuVugiq) zPUU(|8kAI!kZ7t+!gT8pwty7WeI8H{Ql?U)BS4ZioviqA9AOy+!NSy`fI{|>XX7p|;{AtaSlg+WFZJRe8 zP@HKhk+A8~QN=iR_zVK+J_yG_ESCJD<-{37B$7ZZnuMlnAOaZU5Vk@%lz{2xNG5HB zJK~7x3g9f2{-lDG3Q`cH0;E!4q@yd|&T13;!-KuIypzJ0_bvk%V|44c9$K}0)msha z2dbFIXTs#XQ%b-VHok}p&LAa$h>(oh$nTSehPqaW zhyi8kDauO)B?(F@D4_t!pcJ?FbZpbWwACl#YwF;>k;8hoch3R<@J89f{e|Y_)${IH z1S>40VRG~@F2sqd8Vo8a#L3D!NRc}2DN;yF_aQClO%+27&^QB_g4=E2)X6p+-PelF zcssJl11``V{{$%sN>M6o;Bu-uJ~t!w=jDS&bv~RDzjsuxYrt8n?0omJ{na~G{rr(7 zng+w}(?18CF`TMsM8AOrDF5sP0s$X{knngsuwphM;TRa>P!b?p!sqiq*CYaI4DYW$ z3>SHzh(HS6juV7Z;4oEf_>5i=U5|8Q;{7KNG5WH7%`e*&J=^JiXV1X{Ly~PYx^%)Q zSu`-8@7Z-2<4cEQ%Z9xuD9lDMBMn4^&WQ-lUa>*D{0g=}~#&BL=PmB+ut$hyY;0f(0DF9sjy`$&&Bi z@}hS1a5cu44yWDQ%4znk-@tq8wxX@26CRHX!HfXvs+&_yQ4k_l0&UG9)SYNX*{A!U zw`oXcJ_sd2iijzugj94gdIq0|-fNR8GCQH7e*vHq)R%6J_sC#m=gysA`L8lWKX|{Y zhGWy_T?6AW70k&FvXe*aaK)sN>cGC^(3r;h4=O-IeJhk?Xl?2Qk&WXAn(+3@EeI@OV84W~HghiaNF9qk}9rFCBY#RN&*i``FNo89d)L z5MdEQW3mZRrxH;Se=i|VtOl?VKzq0IJ$8leT+iSKWd*J*fjctGFbZzySLo_DZg@7b z{b`6gF`PV62P;By^*hu(|AflobMB%-05&Mgx#t#6T2GD~4HCy_s4oCmiybp53 zUsV7wVd9UxyY^IjM~_I)Oxj3m>+;>C?AkPG?Uuq$!j^ejuGX)*!9Mz?iv@H^?VWQJow*UYD literal 6682 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 diff --git a/res/drawable/warning.png b/res/drawable/warning.png index 42dc6d665cd1cff03f98c1b7b64d7969acf1e3de..f5371dce46c01013261a139b253f2689e9b35ab3 100644 GIT binary patch literal 2735 zcmV;g3Q+ZlP)Exm69lfwG&-+WPfj zPk`-P$iY7&zL=}EGUztc;djsiXMt4T0uZ0fS>7XgYFC1}l5BuuV(AhAin-3#Y7plldE7GUgN4p1BW zWdNsFx(y*Hnj|8wI9xan+Jvv*2c19D?!7esBOf>cclW36XOuO8H4ezA+i)N)v@HdR zFjrmiJ1wH1CB`hmA;#tVAG`$^TPCzW@v8vY6A~ozBya)PQDd$g=T@lu0ve%;Kilf= znz!t-T8YbfxcIkEZp2HHR40MhbpUD1JUaS3)8OQ(9_UTyr2C)+>T5?rqRNtla;HIS zXan!?qx?0ic!9g(g{=73+mfPaAwXmLkAURF?m_EjxqxKltuySTr9W z@e0x!Bd!DYz=ObYC;9CM%z3*Wx}q+`C|!#Jq;?Sy4>es(D|c~(tJv|lU$}(CE74`B zEAM-GfWEhc+wpgxbUH75B5}nCIDh&0VnnqRv>51P79f~I2&^Ert2AsFCQt8}%_B3k@g_Uoirx(KTGF`h;abE*_GZ$8!{kypYPc9VK8wa8Jy0Q7&|W zUjHSmYlOeEqp)*sa>xl3cHGj5sj!I$tzLs^{NgbQh~|}cB}m)SA_OXIy+puM^NYPe z^5;OWYZ2)cW!;byzzW)l0{X-i0B2u9Fxiq@1ORhj5C)#-1!5ai%?**@*VMm|z(UN2 zRs7wp`R#KS4;g{{*4dAumXaE#O`Z4pxihFW%X3Vt!G~ zCFl2nK7NUBg*8J$Aou(%-oLEm+BYV*13R+^vxgfkT7ea^5aTf$A}}IO6an9b{Nm;U z!}?*=%)oAS9JfLfu65twTYzGgpe&)+eg;V99SnvG0t8baWQr^ivC9aUq*wy(&*k9x zvpCMWUj(ypm2ZWWgGwO#r;j#cmRQQLKp7KSft`B|7cU0Dxg|Id79vq$lc)=sGyvak zK7Uuf8#Juo1TBGUC2`G-gJ%Is?**>KNp}J{vsa|e5?D8?QEnB?O14o7;L3^^j^$At zaX)G?r36gF?DUIZHMYq;1En3=XJ<~kYyz1rGcfD0X0WdTBQXtF@0(FgiqBz@7KoW% zpnc0SRQ?aSnG#7@jiXx5Jbtf%G#su177*(rTuGhD{nv|2qO2 z%Cye{aiG#J`F~ZVCESXI=JbD7k>NcR2DH(*(zn8z_eJ31<{KJ#lf|1Yv+-`A$F~F^ zqFNjP5c;#FJ3$OsCXto*l7!2wklGJs;(8$QvAof1LM)x{-2y6Yn)M5Tq>lj0p9yKd zKj^UbxeHZVZm5ydRIA|xfqbdwg%!|Ey`#SY>$)~St-dz`eNRul6${EzMszSIwg5f3 zO)VY`)F==~R#rYH<`y6xmmO(EOvXSk*DLMRqVI46D{yz^p`(3hCNFMD#I)i6w*X~p zIdiM=E@1CG2aIpjS#e;{{(@eaRz}qGgC^+f&w}mm*UTRm3z*99S>H5Mll=mu>| zl5ip8!K|qX1T5=-*xZBK^z+jTY)u%WYU58uYr;f(q7KA*{(;4FAry~4&o?}L&v56v zZYg`8nv5+b%#Gi4KW2mNnD^gCJP1w@(A5!%F2{UP-~}OZeuDp2#DR<&4PavtOJ4+* z>cKqk2=EM8>7)Wm;F%)e6XA^_GqC#4{2pZX+=nSV%ONgEtT?h`KntXPIcYryuaEpN z;x)ia9T1BM?NeX-dej2o6Oq7~f6aP8irD+;8ZL}rTvv9kf%Z#BFATyKD6@jo2lUux zu%<4D{C?40@U*(4UkqG$V&XMujdpI4*o__Fz4aI_T#(JyrLvD#$~-{~s6ggE&vK~w zbRW7xx)cLmGzKEilxHLLZV%fRqh>Ou)iJy-G$Yo|{y|JBrcGLB);9s5-?8k;P~f^{ zFCC~LIV#hj;Bzk=EW+0w&!D8mXVJW=G#YIF`=#JwnX;7f+>B6YZ2D^92`KH680dL? zJpUzS7eB+Sp7&#L_k9Pk_lA63FZsI&T;K0~*O6D@|C$D`pVDB(BdJJiJ+Y<+Zmuu+ zK8pmh8i(?L_T7n!wagjchV0wVfqQ;Gf8|4??m6**rnJA7GmBln0=#3t1y(pO{Wa3( zggVCon>eLK&4WMxGXvRdHX_@)GI-B@msX;9iFMR>bZ7U#Mu<(j$G1Xf&tu~njPt+X zhxyP<>>99Yr-SqI&*e+~02RV}5~bx(=3)K;u1cNafBagV@F0`PL@ZF9sKR^PjoeTs z@`ITUkXHTgUNFY8r$Fm@1tdmrD3ahp{Pi%26z8YWHaTbFzN-Ch-_Z` zO~^p4vFkv4OAID85Xj|nLip$Qmbi+6;=nC9E9+2$Jwq4=2K3=g5S!dA6DVcN488{? z)(9|c8wx#L7!zP~F=u#o0O-uKgI!GjS62D^VX0d~HT7ux@HG6vS! zEVe@hSyk1q94u1Q$}Pd9CBiYnt>C1P#8Y5RS_p;1&ms+e+-+7v@z9fE(;@S?IBHT4 zOEN6@jP-y;T_>FX`81mHz(j3*_F7qHSa&bbKGdY^1BCwd0Q{OTaBv5N@JhRP1F5@1 zD1%$zRj=>(9M2eqz&r_p`?q)z*KC*w6=O`DI19gLiUhyP#D<+Kx`KoEF32(FG4Tos zQe8tN`o%*T306La-L7+Tj~M3`*o~ue@~I4%dNpVyufX{lRSCEJeojfImPen5Ov__4{QEVX_L=iO@AX%^x$<b4-L)~Z8L_`=@GT?%V~oxxv)xzO pAF8Cp?-SjRR9)47Zu4IO1_0|Qs5C&b3s?XE002ovPDHLkV1l8uA{hVx literal 2922 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 diff --git a/res/layout/layout_wizard_permissions.xml b/res/layout/layout_wizard_permissions.xml index 1ba5fec1..1327f151 100644 --- a/res/layout/layout_wizard_permissions.xml +++ b/res/layout/layout_wizard_permissions.xml @@ -7,23 +7,36 @@ - - + + + + android:layout_centerInParent="true" + android:paddingLeft="5sp" + > - + + @@ -37,9 +50,9 @@ > - - - + + + diff --git a/res/layout/layout_wizard_tips.xml b/res/layout/layout_wizard_tips.xml index 17ddb88d..0a7f07b2 100644 --- a/res/layout/layout_wizard_tips.xml +++ b/res/layout/layout_wizard_tips.xml @@ -5,24 +5,38 @@ android:layout_width="fill_parent" android:layout_height="fill_parent"> + - + + + + android:layout_centerInParent="true" + android:paddingLeft="5sp" + > - + @@ -43,12 +57,15 @@ > +