commit 8e8445c1d47644e6e34fc1b96d6934a9aa13f58b Author: Georg Koppen gk@torproject.org Date: Thu Nov 22 14:58:20 2018 +0000
28051 --- build.gradle | 4 ++ mobile/android/app/000-tor-browser-android.js | 3 -- mobile/android/app/build.gradle | 11 +++++ mobile/android/base/AndroidManifest.xml.in | 1 + .../base/java/org/mozilla/gecko/BrowserApp.java | 53 ++++++++++------------ .../base/java/org/mozilla/gecko/GeckoApp.java | 29 ++++++++++++ .../java/org/mozilla/gecko/GeckoApplication.java | 5 ++ .../java/org/mozilla/gecko/LauncherActivity.java | 18 ++++++++ .../gecko/notifications/NotificationClient.java | 6 ++- .../gecko/notifications/NotificationHelper.java | 5 +- mobile/android/config/proguard/proguard.cfg | 15 ++++++ .../java/org/mozilla/gecko/util/ProxySelector.java | 4 +- 12 files changed, 116 insertions(+), 38 deletions(-)
diff --git a/build.gradle b/build.gradle index a080e15b2fac..6cf2d4cc0e7a 100644 --- a/build.gradle +++ b/build.gradle @@ -32,6 +32,10 @@ allprojects { url repository } } + // These are needed for Orbot's dependencies + maven { url "https://raw.githubusercontent.com/guardianproject/gpmaven/master" } + maven { url 'https://jitpack.io' } + jcenter() } }
diff --git a/mobile/android/app/000-tor-browser-android.js b/mobile/android/app/000-tor-browser-android.js index c329fcdee5f7..e7e337276acb 100644 --- a/mobile/android/app/000-tor-browser-android.js +++ b/mobile/android/app/000-tor-browser-android.js @@ -54,9 +54,6 @@ pref("media.realtime_decoder.enabled", false); pref("general.useragent.updates.enabled", false); pref("general.useragent.updates.url", "");
-// Override this because Orbot uses 9050 as the default -pref("network.proxy.socks_port", 9050); - // Do not allow the user to install extensions from web pref("xpinstall.enabled", false); pref("extensions.enabledScopes", 1); diff --git a/mobile/android/app/build.gradle b/mobile/android/app/build.gradle index 7c515bbe65a7..d0060901b6b3 100644 --- a/mobile/android/app/build.gradle +++ b/mobile/android/app/build.gradle @@ -225,6 +225,9 @@ dependencies { implementation "com.android.support:design:${mozconfig.substs.ANDROID_SUPPORT_LIBRARY_VERSION}" implementation "com.android.support:customtabs:${mozconfig.substs.ANDROID_SUPPORT_LIBRARY_VERSION}" implementation "com.android.support:palette-v7:${mozconfig.substs.ANDROID_SUPPORT_LIBRARY_VERSION}" + implementation files('Orbot-16.0.5-RC-1-tor-0.3.4.9-fullperm-release.aar') + implementation files('orbotservice-release.aar') + implementation files('jsocksAndroid-release.aar')
if (mozconfig.substs.MOZ_NATIVE_DEVICES) { implementation "com.android.support:mediarouter-v7:${mozconfig.substs.ANDROID_SUPPORT_LIBRARY_VERSION}" @@ -262,6 +265,14 @@ dependencies {
// Including the Robotium JAR directly can cause issues with dexing. androidTestImplementation 'com.jayway.android.robotium:robotium-solo:5.5.4' + + // Orbot + implementation 'com.github.delight-im:Android-Languages:v1.0.1' + implementation 'pl.bclogic:pulsator4droid:1.0.3' + + // Orbotservice + implementation 'org.torproject:tor-android-binary:0.3.4.9' + implementation 'com.jrummyapps:android-shell:1.0.1' }
// TODO: (bug 1261486): This impl is not robust - diff --git a/mobile/android/base/AndroidManifest.xml.in b/mobile/android/base/AndroidManifest.xml.in index c4ea9a37683e..0e5f4edaf814 100644 --- a/mobile/android/base/AndroidManifest.xml.in +++ b/mobile/android/base/AndroidManifest.xml.in @@ -24,6 +24,7 @@ #include FennecManifest_permissions.xml.in
<application android:label="@string/moz_app_displayname" + tools:replace="android:label" android:icon="@drawable/icon" android:logo="@drawable/logo" android:name="@MOZ_ANDROID_APPLICATION_CLASS@" diff --git a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java index 5efd83398775..42b9ebd0a3f7 100644 --- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java @@ -181,7 +181,8 @@ import org.mozilla.gecko.widget.GeckoActionProvider; import org.mozilla.gecko.widget.SplashScreen; import org.mozilla.geckoview.GeckoSession;
-import info.guardianproject.netcipher.proxy.OrbotHelper; +import org.torproject.android.OrbotMainActivity; +import org.torproject.android.service.TorServiceConstants;
import java.io.File; import java.io.FileNotFoundException; @@ -239,6 +240,9 @@ public class BrowserApp extends GeckoApp public static final int ACTIVITY_REQUEST_TRIPLE_READERVIEW = 4001; public static final int ACTIVITY_RESULT_TRIPLE_READERVIEW_ADD_BOOKMARK = 4002; public static final int ACTIVITY_RESULT_TRIPLE_READERVIEW_IGNORE = 4003; + public static final int ACTIVITY_RESULT_ORBOT_LAUNCH = 5001; + + private static boolean mOrbotRun = false;
public static final String ACTION_VIEW_MULTIPLE = AppConstants.ANDROID_PACKAGE_NAME + ".action.VIEW_MULTIPLE";
@@ -1282,41 +1286,26 @@ public class BrowserApp extends GeckoApp
@Override public void onReceive(Context context, Intent intent) { - if (TextUtils.equals(intent.getAction(), OrbotHelper.ACTION_STATUS)) { + if (TextUtils.equals(intent.getAction(), TorServiceConstants.ACTION_STATUS)) { GeckoAppShell.setTorStatus(intent); } } };
public void checkStartOrbot() { - if (!OrbotHelper.isOrbotInstalled(this)) { - final Intent installOrbotIntent = OrbotHelper.getOrbotInstallIntent(this); + /* run in thread so Tor status updates will be received while the + * Gecko event sync is blocking the main thread */ + HandlerThread handlerThread = new HandlerThread("torStatusReceiver"); + handlerThread.start(); + Looper looper = handlerThread.getLooper(); + Handler handler = new Handler(looper); + registerReceiver(torStatusReceiver, new IntentFilter(TorServiceConstants.ACTION_STATUS), + null, handler);
- AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.install_orbot); - builder.setMessage(R.string.you_must_have_orbot); - builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - startActivity(installOrbotIntent); - } - }); - builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - } - }); - builder.show(); - } else { - /* run in thread so Tor status updates will be received while the - * Gecko event sync is blocking the main thread */ - HandlerThread handlerThread = new HandlerThread("torStatusReceiver"); - handlerThread.start(); - Looper looper = handlerThread.getLooper(); - Handler handler = new Handler(looper); - registerReceiver(torStatusReceiver, new IntentFilter(OrbotHelper.ACTION_STATUS), - null, handler); - OrbotHelper.requestStartTor(this); + if (!mOrbotRun) { + final String orbotStartAction = "android.intent.action.MAIN"; + final Intent launchOrbot = new Intent(orbotStartAction, null, this, OrbotMainActivity.class); + startActivityForResult(launchOrbot, ACTIVITY_RESULT_ORBOT_LAUNCH, null); } }
@@ -3018,6 +3007,12 @@ public class BrowserApp extends GeckoApp TabQueueHelper.processTabQueuePromptResponse(resultCode, this); break;
+ case ACTIVITY_RESULT_ORBOT_LAUNCH: + final SafeIntent intent = new SafeIntent(getIntent()); + Log.d(LOGTAG, "onActivityResult: ACTIVITY_RESULT_ORBOT_LAUNCH"); + mOrbotRun = true; + break; + default: for (final BrowserAppDelegate delegate : delegates) { delegate.onActivityResult(this, requestCode, resultCode, data); diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java index 63a136541970..ef7da17e19a1 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java @@ -91,6 +91,8 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject;
+import org.torproject.android.service.TorService; + import java.io.File; import java.util.ArrayList; import java.util.HashMap; @@ -592,6 +594,9 @@ public abstract class GeckoApp extends GeckoActivity
EventDispatcher.getInstance().dispatch("Browser:Quit", res);
+ Intent torService = new Intent(this, TorService.class); + stopService(torService); + // We don't call shutdown here because this creates a race condition which // can cause the clearing of private data to fail. Instead, we shut down the // UI only after we're done sanitizing. @@ -1201,6 +1206,30 @@ public abstract class GeckoApp extends GeckoActivity } } } + } else if (mIsRestoringActivity) { + /* Synchronize Tabs state with Gecko. We're restoring the Activity, this + * mean all of the Chrome state was lost, but the previously created + * Tabs still exist within the Android application, because those are + * static and the application keeps track of those (and only the Activity + * is starting, the application was never destroyed). */ + Iterable<Tab> tabs = Tabs.getInstance().getTabsInOrder(); + Tab selectedTab = Tabs.getInstance().getSelectedTab(); + for (Tab tab : tabs) { + GeckoBundle reloadMessage = new GeckoBundle(); + reloadMessage.putString("url", tab.getURL()); + reloadMessage.putString("engine", null); + reloadMessage.putInt("parentId", tab.getParentId()); + reloadMessage.putBoolean("userEntered", true); + reloadMessage.putBoolean("isPrivate", tab.isPrivate()); + reloadMessage.putBoolean("pinned", false); + reloadMessage.putBoolean("desktopMode", tab.getDesktopMode()); + reloadMessage.putString("referrerURI", null); + reloadMessage.putInt("tabID", tab.getId()); + reloadMessage.putBoolean("newTab", true); + reloadMessage.putBoolean("delayLoad", selectedTab != tab); + reloadMessage.putBoolean("selected", selectedTab == tab); + getAppEventDispatcher().dispatch("Tab:Load", reloadMessage); + } }
synchronized (GeckoApp.this) { diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java index e896134e0af9..b38e7184c798 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java @@ -62,6 +62,8 @@ import java.lang.reflect.Method; import java.net.URL; import java.util.UUID;
+import org.torproject.android.service.util.Prefs; + public class GeckoApplication extends Application implements HapticFeedbackDelegate { private static final String LOG_TAG = "GeckoApplication"; @@ -319,6 +321,9 @@ public class GeckoApplication extends Application "Profile:Create", null);
+ // Give Orbot the base Context + Prefs.setContext(context); + super.onCreate(); }
diff --git a/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java b/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java index e8f8facc24c6..4cd94ed538c7 100644 --- a/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java +++ b/mobile/android/base/java/org/mozilla/gecko/LauncherActivity.java @@ -45,6 +45,9 @@ import static org.mozilla.gecko.deeplink.DeepLinkContract.LINK_FXA_SIGNIN;
import org.mozilla.gecko.deeplink.DeepLinkContract;
+import org.torproject.android.OrbotMainActivity; +import org.torproject.android.service.TorServiceConstants; + /** * Activity that receives incoming Intents and dispatches them to the appropriate activities (e.g. browser, custom tabs, web app). */ @@ -67,6 +70,9 @@ public class LauncherActivity extends Activity { } else if (isWebAppIntent(safeIntent)) { dispatchWebAppIntent();
+ } else if (TorServiceConstants.TOR_APP_USERNAME.equals(getIntent().getAction())) { + dispatchOrbotIntent(); + // If it's not a view intent, it won't be a custom tabs intent either. Just launch! } else if (!isViewIntentWithURL(safeIntent)) { dispatchNormalIntent(); @@ -116,6 +122,18 @@ public class LauncherActivity extends Activity { startActivity(intent); }
+ private void dispatchOrbotIntent() { + final String orbotStartAction = "android.intent.action.MAIN"; + final Intent intent = new Intent(orbotStartAction, null, this, OrbotMainActivity.class); + + //When we launch Orbot, we want a new task. + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + + startActivity(intent); + } + private void dispatchUrlIntent(@NonNull String url) { Intent intent = new Intent(getIntent()); intent.setData(Uri.parse(url)); diff --git a/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java b/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java index d8392a801e13..c66d67f32787 100644 --- a/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java +++ b/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationClient.java @@ -28,6 +28,8 @@ import org.mozilla.gecko.NotificationListener; import org.mozilla.gecko.R; import org.mozilla.gecko.util.BitmapUtils;
+import org.torproject.android.service.util.NotificationBuilderCompat; + /** * Client for posting notifications. */ @@ -142,7 +144,7 @@ public final class NotificationClient implements NotificationListener { private void add(final String name, final String imageUrl, final String host, final String alertTitle, final String alertText, final PendingIntent contentIntent, final PendingIntent deleteIntent) { - final NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext) + final NotificationBuilderCompat builder = new NotificationBuilderCompat(mContext) .setContentTitle(alertTitle) .setContentText(alertText) .setSmallIcon(R.drawable.ic_status_logo) @@ -150,7 +152,7 @@ public final class NotificationClient implements NotificationListener { .setDeleteIntent(deleteIntent) .setAutoCancel(true) .setDefaults(Notification.DEFAULT_SOUND) - .setStyle(new NotificationCompat.BigTextStyle() + .setStyle(new Notification.BigTextStyle() .bigText(alertText) .setSummaryText(host));
diff --git a/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationHelper.java b/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationHelper.java index 34ea99882d9a..35366609da49 100644 --- a/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationHelper.java +++ b/mobile/android/base/java/org/mozilla/gecko/notifications/NotificationHelper.java @@ -32,10 +32,11 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.graphics.Bitmap; import android.net.Uri; -import android.support.v4.app.NotificationCompat; import android.support.v4.util.SimpleArrayMap; import android.util.Log;
+import org.torproject.android.service.util.NotificationBuilderCompat; + public final class NotificationHelper implements BundleEventListener { public static final String HELPER_BROADCAST_ACTION = AppConstants.ANDROID_PACKAGE_NAME + ".helperBroadcastAction";
@@ -233,7 +234,7 @@ public final class NotificationHelper implements BundleEventListener { private void showNotification(final GeckoBundle message) { ThreadUtils.assertOnUiThread();
- final NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext); + final NotificationBuilderCompat builder = new NotificationBuilderCompat(mContext);
// These attributes are required final String id = message.getString(ID_ATTR); diff --git a/mobile/android/config/proguard/proguard.cfg b/mobile/android/config/proguard/proguard.cfg index 0be8a745e44b..3d03e3107c72 100644 --- a/mobile/android/config/proguard/proguard.cfg +++ b/mobile/android/config/proguard/proguard.cfg @@ -165,6 +165,21 @@ # See: http://stackoverflow.com/questions/22441366/note-android-support-v4-text-icu... -dontnote android.support.**
+# From https://github.com/square/okhttp/blob/master/okhttp/src/main/resources/META-... +# JSR 305 annotations are for embedding nullability information. +-dontwarn javax.annotation.** + +# A resource is loaded with a relative path so the package of this class must be preserved. +-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase + +# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java. +-dontwarn org.codehaus.mojo.animal_sniffer.* + +# OkHttp platform used only on JVM and when Conscrypt dependency is available. +-dontwarn okhttp3.internal.platform.ConscryptPlatform + +#-keepnames class org.torproject.* + -include "adjust-keeps.cfg"
-include "leakcanary-keeps.cfg" diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ProxySelector.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ProxySelector.java index f05716fe1d09..41c2c7e705a1 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ProxySelector.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/ProxySelector.java @@ -30,8 +30,8 @@ import java.util.List;
public class ProxySelector { private static final String TOR_PROXY_ADDRESS = "127.0.0.1"; - private static final int TOR_SOCKS_PROXY_PORT = 9050; - private static final int TOR_HTTP_PROXY_PORT = 8118; + private static final int TOR_SOCKS_PROXY_PORT = 9150; + private static final int TOR_HTTP_PROXY_PORT = 8218;
public static URLConnection openConnectionWithProxy(URI uri) throws IOException { java.net.ProxySelector ps = java.net.ProxySelector.getDefault();