Bug 1258450 - Move references to SnackbarHelper out of GeckoAppShell. r=snorp,sebastian
authorNick Alexander <nalexander@mozilla.com>
Wed, 30 Mar 2016 10:21:29 -0700
changeset 291280 53b8d9973481a0795c30e6daeac2fae25f8b51ae
parent 291279 99c18eae6af0993af8e505f1d97a778cc336e6f7
child 291281 46a922adb14f8fdbcf2a7539dcafeb3784465313
push id74545
push userkwierso@gmail.com
push dateFri, 01 Apr 2016 23:05:42 +0000
treeherdermozilla-inbound@c410d4e20586 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp, sebastian
bugs1258450
milestone48.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1258450 - Move references to SnackbarHelper out of GeckoAppShell. r=snorp,sebastian The existing code assumes an Activity, not just a Context, but doesn't statically guarantee it. This patch is safe because it dynamically type-checks, but it would be better to declare the member to be an Activity. MozReview-Commit-ID: 9AigV055I5j
mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java
mobile/android/base/java/org/mozilla/gecko/widget/GeckoActionProvider.java
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoAppShell.java
@@ -2,28 +2,25 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.io.OutputStream;
 import java.io.PipedInputStream;
 import java.io.PipedOutputStream;
 import java.net.MalformedURLException;
 import java.net.Proxy;
 import java.net.URISyntaxException;
-import java.net.URL;
 import java.net.URLConnection;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.StringTokenizer;
@@ -33,24 +30,22 @@ import java.util.concurrent.ConcurrentHa
 import android.annotation.SuppressLint;
 import org.mozilla.gecko.annotation.JNITarget;
 import org.mozilla.gecko.annotation.RobocopTarget;
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PanZoomController;
-import org.mozilla.gecko.mozglue.ContextUtils;
 import org.mozilla.gecko.overlays.ui.ShareDialog;
 import org.mozilla.gecko.permissions.Permissions;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoRequest;
 import org.mozilla.gecko.util.HardwareCodecCapabilityUtils;
 import org.mozilla.gecko.util.HardwareUtils;
-import org.mozilla.gecko.util.IOUtils;
 import org.mozilla.gecko.util.NativeEventListener;
 import org.mozilla.gecko.util.NativeJSContainer;
 import org.mozilla.gecko.util.NativeJSObject;
 import org.mozilla.gecko.util.ProxySelector;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.widget.ExternalIntentDuringPrivateBrowsingPromptFragment;
 
 import android.Manifest;
@@ -91,34 +86,31 @@ import android.net.NetworkInfo;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Environment;
 import android.os.Looper;
 import android.os.SystemClock;
 import android.os.Vibrator;
 import android.provider.Browser;
 import android.provider.Settings;
-import android.support.design.widget.Snackbar;
 import android.support.v4.app.FragmentActivity;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.Base64;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.Display;
 import android.view.HapticFeedbackConstants;
 import android.view.Surface;
 import android.view.SurfaceView;
 import android.view.TextureView;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.inputmethod.InputMethodManager;
 import android.webkit.MimeTypeMap;
-import android.webkit.URLUtil;
 import android.widget.AbsoluteLayout;
 
 public class GeckoAppShell
 {
     private static final String LOGTAG = "GeckoAppShell";
 
     // We have static members only.
     private GeckoAppShell() { }
@@ -2532,94 +2524,16 @@ public class GeckoAppShell
                 return "PROXY " + proxy.address().toString();
             case SOCKS:
                 return "SOCKS " + proxy.address().toString();
         }
 
         return "DIRECT";
     }
 
-    /* Downloads the URI pointed to by a share intent, and alters the intent to point to the locally stored file.
-     */
-    public static void downloadImageForIntent(final Intent intent) {
-        final String src = ContextUtils.getStringExtra(intent, Intent.EXTRA_TEXT);
-        if (src == null) {
-            showImageShareFailureSnackbar();
-            return;
-        }
-
-        final File dir = GeckoApp.getTempDirectory();
-
-        if (dir == null) {
-            showImageShareFailureSnackbar();
-            return;
-        }
-
-        GeckoApp.deleteTempFiles();
-
-        String type = intent.getType();
-        OutputStream os = null;
-        try {
-            // Create a temporary file for the image
-            if (src.startsWith("data:")) {
-                final int dataStart = src.indexOf(",");
-
-                String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(type);
-
-                // If we weren't given an explicit mimetype, try to dig one out of the data uri.
-                if (TextUtils.isEmpty(extension) && dataStart > 5) {
-                    type = src.substring(5, dataStart).replace(";base64", "");
-                    extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(type);
-                }
-
-                final File imageFile = File.createTempFile("image", "." + extension, dir);
-                os = new FileOutputStream(imageFile);
-
-                byte[] buf = Base64.decode(src.substring(dataStart + 1), Base64.DEFAULT);
-                os.write(buf);
-
-                // Only alter the intent when we're sure everything has worked
-                intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(imageFile));
-            } else {
-                InputStream is = null;
-                try {
-                    final byte[] buf = new byte[2048];
-                    final URL url = new URL(src);
-                    final String filename = URLUtil.guessFileName(src, null, type);
-                    is = url.openStream();
-
-                    final File imageFile = new File(dir, filename);
-                    os = new FileOutputStream(imageFile);
-
-                    int length;
-                    while ((length = is.read(buf)) != -1) {
-                        os.write(buf, 0, length);
-                    }
-
-                    // Only alter the intent when we're sure everything has worked
-                    intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(imageFile));
-                } finally {
-                    IOUtils.safeStreamClose(is);
-                }
-            }
-        } catch(IOException ex) {
-            // If something went wrong, we'll just leave the intent un-changed
-        } finally {
-            IOUtils.safeStreamClose(os);
-        }
-    }
-
-    // Don't fail silently, tell the user that we weren't able to share the image
-    private static final void showImageShareFailureSnackbar() {
-        SnackbarHelper.showSnackbar((Activity) getContext(),
-                getApplicationContext().getString(R.string.share_image_failed),
-                Snackbar.LENGTH_LONG
-        );
-    }
-
     @WrapForJNI(allowMultithread = true)
     static InputStream createInputStream(URLConnection connection) throws IOException {
         return connection.getInputStream();
     }
 
     private static class BitmapConnection extends URLConnection {
         private Bitmap bitmap;
 
--- a/mobile/android/base/java/org/mozilla/gecko/widget/GeckoActionProvider.java
+++ b/mobile/android/base/java/org/mozilla/gecko/widget/GeckoActionProvider.java
@@ -1,36 +1,52 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.widget;
 
+import android.app.Activity;
+import android.net.Uri;
+import android.support.design.widget.Snackbar;
+import android.util.Base64;
 import android.view.Menu;
-import org.mozilla.gecko.GeckoAppShell;
+
+import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.SnackbarHelper;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.menu.QuickShareBarActionView;
+import org.mozilla.gecko.mozglue.ContextUtils;
 import org.mozilla.gecko.overlays.ui.ShareDialog;
 import org.mozilla.gecko.menu.MenuItemSwitcherLayout;
+import org.mozilla.gecko.util.IOUtils;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.view.MenuItem;
 import android.view.MenuItem.OnMenuItemClickListener;
 import android.view.SubMenu;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.text.TextUtils;
+import android.webkit.MimeTypeMap;
+import android.webkit.URLUtil;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
 
 public class GeckoActionProvider {
     private static final int MAX_HISTORY_SIZE_DEFAULT = 2;
 
     /**
      * A listener to know when a target was selected.
@@ -227,17 +243,17 @@ public class GeckoActionProvider {
             if (launchIntent != null) {
                 // This may cause a download to happen. Make sure we're on the background thread.
                 ThreadUtils.postToBackgroundThread(new Runnable() {
                     @Override
                     public void run() {
                         // Share image downloads the image before sharing it.
                         String type = launchIntent.getType();
                         if (Intent.ACTION_SEND.equals(launchIntent.getAction()) && type != null && type.startsWith("image/")) {
-                            GeckoAppShell.downloadImageForIntent(launchIntent);
+                            downloadImageForIntent(launchIntent);
                         }
 
                         launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
                         mContext.startActivity(launchIntent);
                     }
                 });
             }
 
@@ -265,9 +281,85 @@ public class GeckoActionProvider {
         }
     }
 
     public enum ActionViewType {
         DEFAULT,
         QUICK_SHARE_ICON,
         CONTEXT_MENU,
     }
+
+
+    /**
+     * Downloads the URI pointed to by a share intent, and alters the intent to point to the
+     * locally stored file.
+     *
+     * @param intent share intent to alter in place.
+     */
+    public void downloadImageForIntent(final Intent intent) {
+        final String src = ContextUtils.getStringExtra(intent, Intent.EXTRA_TEXT);
+        final File dir = GeckoApp.getTempDirectory();
+
+        if (src == null || dir == null) {
+            // We should be, but currently aren't, statically guaranteed an Activity context.
+            // Try our best.
+            if (mContext instanceof Activity) {
+                SnackbarHelper.showSnackbar((Activity) mContext,
+                        mContext.getApplicationContext().getString(R.string.share_image_failed),
+                        Snackbar.LENGTH_LONG);
+            }
+            return;
+        }
+
+        GeckoApp.deleteTempFiles();
+
+        String type = intent.getType();
+        OutputStream os = null;
+        try {
+            // Create a temporary file for the image
+            if (src.startsWith("data:")) {
+                final int dataStart = src.indexOf(",");
+
+                String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(type);
+
+                // If we weren't given an explicit mimetype, try to dig one out of the data uri.
+                if (TextUtils.isEmpty(extension) && dataStart > 5) {
+                    type = src.substring(5, dataStart).replace(";base64", "");
+                    extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(type);
+                }
+
+                final File imageFile = File.createTempFile("image", "." + extension, dir);
+                os = new FileOutputStream(imageFile);
+
+                byte[] buf = Base64.decode(src.substring(dataStart + 1), Base64.DEFAULT);
+                os.write(buf);
+
+                // Only alter the intent when we're sure everything has worked
+                intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(imageFile));
+            } else {
+                InputStream is = null;
+                try {
+                    final byte[] buf = new byte[2048];
+                    final URL url = new URL(src);
+                    final String filename = URLUtil.guessFileName(src, null, type);
+                    is = url.openStream();
+
+                    final File imageFile = new File(dir, filename);
+                    os = new FileOutputStream(imageFile);
+
+                    int length;
+                    while ((length = is.read(buf)) != -1) {
+                        os.write(buf, 0, length);
+                    }
+
+                    // Only alter the intent when we're sure everything has worked
+                    intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(imageFile));
+                } finally {
+                    IOUtils.safeStreamClose(is);
+                }
+            }
+        } catch(IOException ex) {
+            // If something went wrong, we'll just leave the intent un-changed
+        } finally {
+            IOUtils.safeStreamClose(os);
+        }
+    }
 }