Bug 1391268 - 4. Display message when APK is corrupt; r?snorp draft
authorJim Chen <nchen@mozilla.com>
Wed, 31 Jan 2018 15:34:18 -0500
changeset 749618 ae0c2ce35aaca45149af26eb2649a79305bde2e3
parent 749617 9e0791e673e47a159b07ddd15062682a5dde8181
push id97462
push userbmo:nchen@mozilla.com
push dateWed, 31 Jan 2018 20:35:46 +0000
reviewerssnorp
bugs1391268
milestone60.0a1
Bug 1391268 - 4. Display message when APK is corrupt; r?snorp Display a message on startup when the APK is corrupt. Right now the "wrong SDK" message is displayed. I think we can potentially reuse that message for Beta, but we need a different message for Nightly. MozReview-Commit-ID: 9NEw252Ytkc
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/strings.xml.in
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -617,27 +617,16 @@ public class BrowserApp extends GeckoApp
     }
 
     @Override
     public void onCreate(Bundle savedInstanceState) {
         final Context appContext = getApplicationContext();
 
         showSplashScreen = true;
 
-        boolean supported = HardwareUtils.isSupportedSystem();
-        if (supported) {
-            GeckoLoader.loadMozGlue(appContext);
-            supported = GeckoLoader.neonCompatible();
-        }
-        if (!supported) {
-            // This build does not support the Android version of the device; Exit early.
-            super.onCreate(savedInstanceState);
-            return;
-        }
-
         final SafeIntent intent = new SafeIntent(getIntent());
         final boolean isInAutomation = IntentUtils.getIsInAutomationFromEnvironment(intent);
 
         GeckoProfile.setIntentArgs(intent.getStringExtra("args"));
 
         if (!isInAutomation && AppConstants.MOZ_ANDROID_DOWNLOAD_CONTENT_SERVICE) {
             // Kick off download of app content as early as possible so that in the best case it's
             // available before the user starts using the browser.
@@ -647,16 +636,20 @@ public class BrowserApp extends GeckoApp
         // This has to be prepared prior to calling GeckoApp.onCreate, because
         // widget code and BrowserToolbar need it, and they're created by the
         // layout, which GeckoApp takes care of.
         final GeckoApplication app = (GeckoApplication) getApplication();
         app.prepareLightweightTheme();
 
         super.onCreate(savedInstanceState);
 
+        if (mIsAbortingAppLaunch) {
+          return;
+        }
+
         initSwitchboard(this, intent, isInAutomation);
         initTelemetryUploader(isInAutomation);
 
         mBrowserChrome = (ViewGroup) findViewById(R.id.browser_chrome);
         mActionBarFlipper = (ViewFlipper) findViewById(R.id.browser_actionbar);
         mActionBar = (ActionModeCompatView) findViewById(R.id.actionbar);
 
         mVideoPlayer = (VideoPlayer) findViewById(R.id.video_player);
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -652,16 +652,22 @@ public abstract class GeckoApp extends G
             // Reset the crash loop counter if we remain alive for at least half a minute.
             ThreadUtils.postDelayedToBackgroundThread(new Runnable() {
                 @Override
                 public void run() {
                     getSharedPreferences().edit().putInt(PREFS_CRASHED_COUNT, 0).apply();
                 }
             }, STARTUP_PHASE_DURATION_MS);
 
+        } else if (event.equals("Gecko:CorruptAPK")) {
+            showCorruptAPKError();
+            if (!isFinishing()) {
+                finish();
+            }
+
         } else if ("Accessibility:Ready".equals(event)) {
             GeckoAccessibility.updateAccessibilitySettings(this);
 
         } else if ("Accessibility:Event".equals(event)) {
             GeckoAccessibility.sendAccessibilityEvent(mLayerView, message);
 
         } else if ("Contact:Add".equals(event)) {
             final String email = message.getString("email");
@@ -899,26 +905,32 @@ public abstract class GeckoApp extends G
      **/
     @Override
     public void onCreate(Bundle savedInstanceState) {
         // Enable Android Strict Mode for developers' local builds (the "default" channel).
         if ("default".equals(AppConstants.MOZ_UPDATE_CHANNEL)) {
             enableStrictMode();
         }
 
+        final boolean corruptAPK = GeckoThread.isState(GeckoThread.State.CORRUPT_APK);
         boolean supported = HardwareUtils.isSupportedSystem();
         if (supported) {
             GeckoLoader.loadMozGlue(getApplicationContext());
             supported = GeckoLoader.neonCompatible();
         }
-        if (!supported) {
-            // This build does not support the Android version of the device: Show an error and finish the app.
+        if (corruptAPK || !supported) {
+            // This build is corrupt or does not support the Android version of the device.
+            // Show an error and finish the app.
             mIsAbortingAppLaunch = true;
             super.onCreate(savedInstanceState);
-            showSDKVersionError();
+            if (corruptAPK) {
+                showCorruptAPKError();
+            } else {
+                showSDKVersionError();
+            }
             finish();
             return;
         }
 
         // The clock starts...now. Better hurry!
         mJavaUiStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_JAVAUI");
         mGeckoReadyStartupTimer = new Telemetry.UptimeTimer("FENNEC_STARTUP_TIME_GECKOREADY");
 
@@ -993,16 +1005,17 @@ public abstract class GeckoApp extends G
 
         // To prevent races, register startup events before launching the Gecko thread.
         EventDispatcher.getInstance().registerGeckoThreadListener(this,
             "Accessibility:Ready",
             "Gecko:Ready",
             null);
 
         EventDispatcher.getInstance().registerUiThreadListener(this,
+            "Gecko:CorruptAPK",
             "Update:Check",
             "Update:Download",
             "Update:Install",
             null);
 
         GeckoThread.launch();
 
         Bundle stateBundle = IntentUtils.getBundleExtraSafe(getIntent(), EXTRA_STATE_BUNDLE);
@@ -2039,16 +2052,17 @@ public abstract class GeckoApp extends G
         }
 
         EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
             "Accessibility:Ready",
             "Gecko:Ready",
             null);
 
         EventDispatcher.getInstance().unregisterUiThreadListener(this,
+            "Gecko:CorruptAPK",
             "Update:Check",
             "Update:Download",
             "Update:Install",
             null);
 
         getAppEventDispatcher().unregisterGeckoThreadListener(this,
             "Locale:Set",
             null);
@@ -2099,16 +2113,20 @@ public abstract class GeckoApp extends G
     }
 
     public void showSDKVersionError() {
         final String message = getString(R.string.unsupported_sdk_version,
                 HardwareUtils.getRealAbi(), Integer.toString(Build.VERSION.SDK_INT));
         Toast.makeText(this, message, Toast.LENGTH_LONG).show();
     }
 
+    private void showCorruptAPKError() {
+        Toast.makeText(this, getString(R.string.corrupt_apk), Toast.LENGTH_LONG).show();
+    }
+
     // Get a temporary directory, may return null
     public static File getTempDirectory(@NonNull Context context) {
         return context.getApplicationContext().getExternalFilesDir("temp");
     }
 
     // Delete any files in our temporary directory
     public static void deleteTempFiles(Context context) {
         File dir = getTempDirectory(context);
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -807,16 +807,19 @@ just addresses the organization to follo
 <!-- LOCALIZATION NOTE (bookmarks_restricted_webmaker):link title for https://webmaker.org -->
 <!ENTITY bookmarks_restricted_webmaker "Learn the Web: Mozilla Webmaker">
 
 <!-- LOCALIZATION NOTE (unsupported_sdk_version): The user installed a build of this app that does not support
      the Android version of this device. the formatS1 is replaced by the CPU ABI (e.g., ARMv7); the formatS2 is
      replaced by the Android OS version (e.g., 14)-->
 <!ENTITY unsupported_sdk_version "Sorry! This &brandShortName; won\'t work on this device (&formatS1;, &formatS2;). Please download the correct version.">
 
+<!-- LOCALIZATION NOTE(corrupt_apk): This notification is shown if corruption has been detected on startup and the user has to reinstall Firefox -->
+<!ENTITY corrupt_apk "Unable to open &brandShortName;. Please reinstall and try again.">
+
 <!ENTITY eol_notification_title2 "&brandShortName; will no longer update">
 <!ENTITY eol_notification_summary "Tap to learn more">
 
 <!-- LOCALIZATION NOTE (whatsnew_notification_title, whatsnew_notification_summary): These strings
      are used for a system notification that's shown to users after the app updates. -->
 <!ENTITY whatsnew_notification_title "&brandShortName; is up to date">
 <!ENTITY whatsnew_notification_summary "Find out what\'s new in this version">
 
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -593,16 +593,17 @@
   <string name="remote_tabs_last_synced">&remote_tabs_last_synced;</string>
 
   <string name="intent_uri_private_browsing_prompt">&intent_uri_private_browsing_prompt;</string>
   <string name="intent_uri_private_browsing_multiple_match_title">&intent_uri_private_browsing_multiple_match_title;</string>
 
   <string name="devtools_auth_scan_header">&devtools_auth_scan_header;</string>
 
   <string name="unsupported_sdk_version">&unsupported_sdk_version;</string>
+  <string name="corrupt_apk">&corrupt_apk;</string>
   <string name="eol_notification_title">&eol_notification_title2;</string>
   <string name="eol_notification_summary">&eol_notification_summary;</string>
   <!-- https://support.mozilla.org/1/mobile/%VERSION%/%OS%/%LOCALE%/honeycomb -->
   <string name="eol_notification_url">https://support.mozilla.org/1/mobile/&formatS1;/&formatS2;/&formatS3;/unsupported-version</string>
 
   <string name="whatsnew_notification_title">&whatsnew_notification_title;</string>
   <string name="whatsnew_notification_summary">&whatsnew_notification_summary;</string>
   <!-- https://support.mozilla.org/1/mobile/%VERSION%/%OS%/%LOCALE%/new-android -->