diff --git a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
index 71d5787fbf4e..4f5563ae0a7b 100644
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -5,6 +5,7 @@
package org.mozilla.gecko;
+import android.Manifest;
import android.os.AsyncTask;
import org.mozilla.gecko.adjust.AdjustHelperInterface;
import org.mozilla.gecko.annotation.RobocopTarget;
@@ -46,6 +47,7 @@ import org.mozilla.gecko.menu.GeckoMenuItem;
import org.mozilla.gecko.mozglue.ContextUtils;
import org.mozilla.gecko.mozglue.ContextUtils.SafeIntent;
import org.mozilla.gecko.overlays.ui.ShareDialog;
+import org.mozilla.gecko.permissions.Permissions;
import org.mozilla.gecko.preferences.ClearOnShutdownPref;
import org.mozilla.gecko.preferences.GeckoPreferences;
import org.mozilla.gecko.prompts.Prompt;
@@ -65,6 +67,7 @@ import org.mozilla.gecko.toolbar.BrowserToolbar;
import org.mozilla.gecko.toolbar.BrowserToolbar.TabEditingState;
import org.mozilla.gecko.toolbar.ToolbarProgressView;
import org.mozilla.gecko.trackingprotection.TrackingProtectionPrompt;
+import org.mozilla.gecko.updater.UpdateServiceHelper;
import org.mozilla.gecko.util.ActivityUtils;
import org.mozilla.gecko.util.Clipboard;
import org.mozilla.gecko.util.EventCallback;
@@ -754,6 +757,39 @@ public class BrowserApp extends GeckoApp
// Set the maximum bits-per-pixel the favicon system cares about.
IconDirectoryEntry.setMaxBPP(GeckoAppShell.getScreenDepth());
+
+ // The update service is enabled for RELEASE_BUILD, which includes the release and beta channels.
+ // However, no updates are served. Therefore, we don't trust the update service directly, and
+ // try to avoid prompting unnecessarily. See Bug 1232798.
+ if (!AppConstants.RELEASE_BUILD && UpdateServiceHelper.isUpdaterEnabled()) {
+ Permissions.from(this)
+ .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ .doNotPrompt()
+ .andFallback(new Runnable() {
+ @Override
+ public void run() {
+ showUpdaterPermissionSnackbar();
+ }
+ })
+ .run();
+ }
+ }
+
+ private void showUpdaterPermissionSnackbar() {
+ SnackbarHelper.SnackbarCallback allowCallback = new SnackbarHelper.SnackbarCallback() {
+ @Override
+ public void onClick(View v) {
+ Permissions.from(BrowserApp.this)
+ .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ .run();
+ }
+ };
+
+ SnackbarHelper.showSnackbarWithAction(this,
+ getString(R.string.updater_permission_text),
+ Snackbar.LENGTH_INDEFINITE,
+ getString(R.string.updater_permission_allow),
+ allowCallback);
}
private void conditionallyNotifyHCEOL() {
diff --git a/mobile/android/base/java/org/mozilla/gecko/permissions/PermissionBlock.java b/mobile/android/base/java/org/mozilla/gecko/permissions/PermissionBlock.java
index 208ebfadcfef..a4d72f2584ee 100644
--- a/mobile/android/base/java/org/mozilla/gecko/permissions/PermissionBlock.java
+++ b/mobile/android/base/java/org/mozilla/gecko/permissions/PermissionBlock.java
@@ -65,11 +65,18 @@ public class PermissionBlock {
return this;
}
+ /**
+ * Execute this permission block. Calling this method will prompt the user if needed.
+ */
+ public void run() {
+ run(null);
+ }
+
/**
* Execute the specified runnable if the app has been granted all permissions. Calling this method will prompt the
* user if needed.
*/
- public void run(@NonNull Runnable onPermissionsGranted) {
+ public void run(Runnable onPermissionsGranted) {
if (!doNotPrompt && !(context instanceof Activity)) {
throw new IllegalStateException("You need to either specify doNotPrompt() or pass in an Activity context");
}
diff --git a/mobile/android/base/strings.xml.in b/mobile/android/base/strings.xml.in
index 23532a60127a..6a513aa54a08 100644
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -541,6 +541,7 @@
&brandShortName;
&updater_permission_text;
+ &updater_permission_allow;
&suggestions_prompt3;