Bug 776027 - Move intent handling to IntentHelper. r=wesj
☠☠ backed out by c300fbbd1b1e ☠ ☠
authorJosh Dover <gerfuls@gmail.com>
Mon, 14 Apr 2014 17:46:00 +0200
changeset 178395 33bcd13d52f59caaed9607a526cd261cf2399743
parent 178394 623749c030653204c3e720ff901aa39e86b49944
child 178396 f8c51b2092cad9b1d86035a80bf7074e0741f58e
push id6314
push usercbook@mozilla.com
push dateTue, 15 Apr 2014 09:15:50 +0000
treeherderfx-team@b90d50c9d8be [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswesj
bugs776027
milestone31.0a1
Bug 776027 - Move intent handling to IntentHelper. r=wesj
mobile/android/base/GeckoApp.java
mobile/android/base/IntentHelper.java
mobile/android/base/moz.build
mobile/android/base/util/JSONUtils.java
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -664,59 +664,17 @@ public abstract class GeckoApp
                     startActivity(i);
                 } else if (!message.isNull("phone")) {
                     Uri contactUri = Uri.parse(message.getString("phone"));       
                     Intent i = new Intent(ContactsContract.Intents.SHOW_OR_CREATE_CONTACT, contactUri);
                     startActivity(i);
                 } else {
                     // something went wrong.
                     Log.e(LOGTAG, "Received Contact:Add message with no email nor phone number");
-                }                
-            } else if (event.equals("Intent:GetHandlers")) {
-                Intent intent = GeckoAppShell.getOpenURIIntent((Context) this, message.optString("url"),
-                    message.optString("mime"), message.optString("action"), message.optString("title"));
-                String[] handlers = GeckoAppShell.getHandlersForIntent(intent);
-                List<String> appList = Arrays.asList(handlers);
-                JSONObject handlersJSON = new JSONObject();
-                handlersJSON.put("apps", new JSONArray(appList));
-                EventDispatcher.sendResponse(message, handlersJSON);
-            } else if (event.equals("Intent:Open")) {
-                GeckoAppShell.openUriExternal(message.optString("url"),
-                    message.optString("mime"), message.optString("packageName"),
-                    message.optString("className"), message.optString("action"), message.optString("title"));
-            } else if (event.equals("Intent:OpenForResult")) {
-                Intent intent = GeckoAppShell.getOpenURIIntent(this,
-                                                               message.optString("url"),
-                                                               message.optString("mime"),
-                                                               message.optString("action"),
-                                                               message.optString("title"));
-                intent.setClassName(message.optString("packageName"), message.optString("className"));
-
-                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
-
-                final JSONObject originalMessage = message;
-                ActivityHandlerHelper.startIntentForActivity(this,
-                                                             intent,
-                        new ActivityResultHandler() {
-                            @Override
-                            public void onActivityResult (int resultCode, Intent data) {
-                                JSONObject response = new JSONObject();
-
-                                try {
-                                    if (data != null) {
-                                        response.put("extras", bundleToJSON(data.getExtras()));
-                                    }
-                                    response.put("resultCode", resultCode);
-                                } catch (JSONException e) {
-                                    Log.w(LOGTAG, "Error building JSON response.", e);
-                                }
-
-                                EventDispatcher.sendResponse(originalMessage, response);
-                            }
-                        });
+                }
             } else if (event.equals("Locale:Set")) {
                 setLocale(message.getString("locale"));
             } else if (event.equals("NativeApp:IsDebuggable")) {
                 JSONObject ret = new JSONObject();
                 ret.put("isDebuggable", getIsDebuggable());
                 EventDispatcher.sendResponse(message, ret);
             } else if (event.equals("SystemUI:Visibility")) {
                 setSystemUiVisible(message.getBoolean("visible"));
@@ -867,33 +825,16 @@ public abstract class GeckoApp
                             GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Toast:Hidden", buttonId));
                         }
                     }
                 });
             }
         });
     }
 
-    private JSONObject bundleToJSON(Bundle bundle) {
-        JSONObject json = new JSONObject();
-        if (bundle == null) {
-            return json;
-        }
-
-        for (String key : bundle.keySet()) {
-            try {
-                json.put(key, bundle.get(key));
-            } catch (JSONException e) {
-                Log.w(LOGTAG, "Error building JSON response.", e);
-            }
-        }
-
-        return json;
-    }
-
     private void addFullScreenPluginView(View view) {
         if (mFullScreenPluginView != null) {
             Log.w(LOGTAG, "Already have a fullscreen plugin view");
             return;
         }
 
         setFullScreen(true);
 
@@ -1382,16 +1323,17 @@ public abstract class GeckoApp
                         GeckoApp.this.onLocaleReady(uiLocale);
                     }
                 });
             }
         });
 
         GeckoAppShell.setNotificationClient(makeNotificationClient());
         NotificationHelper.init(getApplicationContext());
+        IntentHelper.init(this);
     }
 
     /**
      * At this point, the resource system and the rest of the browser are
      * aware of the locale.
      *
      * Now we can display strings!
      */
@@ -1593,19 +1535,16 @@ public abstract class GeckoApp
         registerEventListener("Share:Text");
         registerEventListener("Image:SetAs");
         registerEventListener("Sanitize:ClearHistory");
         registerEventListener("Update:Check");
         registerEventListener("Update:Download");
         registerEventListener("Update:Install");
         registerEventListener("PrivateBrowsing:Data");
         registerEventListener("Contact:Add");
-        registerEventListener("Intent:Open");
-        registerEventListener("Intent:OpenForResult");
-        registerEventListener("Intent:GetHandlers");
         registerEventListener("Locale:Set");
         registerEventListener("NativeApp:IsDebuggable");
         registerEventListener("SystemUI:Visibility");
 
         EventListener.registerEvents();
 
         if (SmsManager.getInstance() != null) {
           SmsManager.getInstance().start();
@@ -2125,18 +2064,16 @@ public abstract class GeckoApp
         unregisterEventListener("Share:Text");
         unregisterEventListener("Image:SetAs");
         unregisterEventListener("Sanitize:ClearHistory");
         unregisterEventListener("Update:Check");
         unregisterEventListener("Update:Download");
         unregisterEventListener("Update:Install");
         unregisterEventListener("PrivateBrowsing:Data");
         unregisterEventListener("Contact:Add");
-        unregisterEventListener("Intent:Open");
-        unregisterEventListener("Intent:GetHandlers");
         unregisterEventListener("Locale:Set");
         unregisterEventListener("NativeApp:IsDebuggable");
         unregisterEventListener("SystemUI:Visibility");
 
         EventListener.unregisterEvents();
 
         deleteTempFiles();
 
@@ -2148,16 +2085,17 @@ public abstract class GeckoApp
             mFormAssistPopup.destroy();
         if (mContactService != null)
             mContactService.destroy();
         if (mPromptService != null)
             mPromptService.destroy();
         if (mTextSelection != null)
             mTextSelection.destroy();
         NotificationHelper.destroy();
+        IntentHelper.destroy();
 
         if (SmsManager.getInstance() != null) {
             SmsManager.getInstance().stop();
             if (isFinishing())
                 SmsManager.getInstance().shutdown();
         }
 
         final HealthRecorder rec = mHealthRecorder;
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/IntentHelper.java
@@ -0,0 +1,134 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; 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;
+
+import org.mozilla.gecko.util.ActivityResultHandler;
+import org.mozilla.gecko.util.GeckoEventListener;
+import org.mozilla.gecko.util.JSONUtils;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.net.Uri;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.List;
+
+public final class IntentHelper implements GeckoEventListener {
+    private static final String LOGTAG = "GeckoIntentHelper";
+    private static final String[] EVENTS = {
+        "Intent:GetHandlers",
+        "Intent:Open",
+        "Intent:OpenForResult"
+    };
+    private static IntentHelper instance;
+
+    private Activity activity;
+
+    private IntentHelper(Activity activity) {
+        this.activity = activity;
+        for (String event : EVENTS) {
+            GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
+        }
+    }
+
+    public static IntentHelper init(Activity activity) {
+        if (instance == null) {
+            instance = new IntentHelper(activity);
+        } else {
+            Log.w(LOGTAG, "IntentHelper.init() called twice, ignoring.");
+        }
+
+        return instance;
+    }
+
+    public static void destroy() {
+        if (instance != null) {
+            for (String event : EVENTS) {
+                GeckoAppShell.getEventDispatcher().unregisterEventListener(event, instance);
+            }
+
+            instance = null;
+        }
+    }
+
+    @Override
+    public void handleMessage(String event, JSONObject message) {
+        try {
+            if (event.equals("Intent:GetHandlers")) {
+                getHandlers(message);
+            } else if (event.equals("Intent:Open")) {
+                open(message);
+            } else if (event.equals("Intent:OpenForResult")) {
+                openForResult(message);
+            }
+        } catch (JSONException e) {
+            Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
+        }
+    }
+
+    private void getHandlers(JSONObject message) throws JSONException {
+        final Intent intent = GeckoAppShell.getOpenURIIntent(activity,
+                                                             message.optString("url"),
+                                                             message.optString("mime"),
+                                                             message.optString("action"),
+                                                             message.optString("title"));
+        final List<String> appList = Arrays.asList(GeckoAppShell.getHandlersForIntent(intent));
+
+        final JSONObject response = new JSONObject();
+        response.put("apps", new JSONArray(appList));
+        EventDispatcher.sendResponse(message, response);
+    }
+
+    private void open(JSONObject message) throws JSONException {
+        GeckoAppShell.openUriExternal(message.optString("url"),
+                                      message.optString("mime"),
+                                      message.optString("packageName"),
+                                      message.optString("className"),
+                                      message.optString("action"),
+                                      message.optString("title"));
+    }
+
+    private void openForResult(final JSONObject message) throws JSONException {
+        Intent intent = GeckoAppShell.getOpenURIIntent(activity,
+                                                       message.optString("url"),
+                                                       message.optString("mime"),
+                                                       message.optString("action"),
+                                                       message.optString("title"));
+        intent.setClassName(message.optString("packageName"), message.optString("className"));
+        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+
+        ActivityHandlerHelper.startIntentForActivity(activity, intent, new ResultHandler(message));
+    }
+
+    private static class ResultHandler implements ActivityResultHandler {
+        private final JSONObject message;
+
+        public ResultHandler(JSONObject message) {
+            this.message = message;
+        }
+
+        @Override
+        public void onActivityResult (int resultCode, Intent data) {
+            JSONObject response = new JSONObject();
+
+            try {
+                if (data != null) {
+                    response.put("extras", JSONUtils.bundleToJSON(data.getExtras()));
+                }
+                response.put("resultCode", resultCode);
+            } catch (JSONException e) {
+                Log.w(LOGTAG, "Error building JSON response.", e);
+            }
+
+            EventDispatcher.sendResponse(message, response);
+        }
+    }
+}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -276,16 +276,17 @@ gbjar.sources += [
     'home/SuggestClient.java',
     'home/TabMenuStrip.java',
     'home/TopSitesGridItemView.java',
     'home/TopSitesGridView.java',
     'home/TopSitesPanel.java',
     'home/TopSitesThumbnailView.java',
     'home/TwoLinePageRow.java',
     'InputMethods.java',
+    'IntentHelper.java',
     'JavaAddonManager.java',
     'LightweightTheme.java',
     'LightweightThemeDrawable.java',
     'LocaleManager.java',
     'MediaCastingBar.java',
     'MemoryMonitor.java',
     'menu/GeckoMenu.java',
     'menu/GeckoMenuInflater.java',
--- a/mobile/android/base/util/JSONUtils.java
+++ b/mobile/android/base/util/JSONUtils.java
@@ -2,16 +2,17 @@
  * 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.util;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import android.os.Bundle;
 import android.util.Log;
 
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.UUID;
 
 public final class JSONUtils {
     private static final String LOGTAG = "JSONUtils";
@@ -49,9 +50,26 @@ public final class JSONUtils {
     public static void putUUID(String name, UUID uuid, JSONObject json) {
         String uuidString = uuid.toString();
         try {
             json.put(name, uuidString);
         } catch (JSONException e) {
             throw new IllegalArgumentException(name + "=" + uuidString, e);
         }
     }
+
+    public static JSONObject bundleToJSON(Bundle bundle) {
+        JSONObject json = new JSONObject();
+        if (bundle == null) {
+            return json;
+        }
+
+        for (String key : bundle.keySet()) {
+            try {
+                json.put(key, bundle.get(key));
+            } catch (JSONException e) {
+                Log.w(LOGTAG, "Error building JSON response.", e);
+            }
+        }
+
+        return json;
+    }
 }