Bug 1319496 - 5. Change prompt response to use GeckoBundle; r=sebastian
authorJim Chen <nchen@mozilla.com>
Tue, 29 Nov 2016 12:25:53 -0500
changeset 324721 5e8406f38c0936d8626a9dc0debc23b5ea7138bd
parent 324720 16dbb57af3e2888827ef2db6d6e17d28cdab1379
child 324722 15d6ef5ef0e2dfba731d4045813bf0f3828eb5b8
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewerssebastian
bugs1319496
milestone53.0a1
Bug 1319496 - 5. Change prompt response to use GeckoBundle; r=sebastian Change prompt response from using JSONObject/String to using GeckoBundle. The GeckoBundle is automatically translated to a JS object, like before, when dispatched to JS code.
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
mobile/android/base/java/org/mozilla/gecko/delegates/BookmarkStateChangeDelegate.java
mobile/android/base/java/org/mozilla/gecko/prompts/IntentChooserPrompt.java
mobile/android/base/java/org/mozilla/gecko/prompts/Prompt.java
mobile/android/base/java/org/mozilla/gecko/prompts/PromptService.java
mobile/android/base/java/org/mozilla/gecko/prompts/TabInput.java
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -3828,34 +3828,32 @@ public class BrowserApp extends GeckoApp
     public void showGuestModeDialog(final GuestModeDialog type) {
         if ((type == GuestModeDialog.ENTERING) == getProfile().inGuestMode()) {
             // Don't show enter dialog if we are already in guest mode; same with leaving.
             return;
         }
 
         final Prompt ps = new Prompt(this, new Prompt.PromptCallback() {
             @Override
-            public void onPromptFinished(String result) {
-                try {
-                    int itemId = new JSONObject(result).getInt("button");
-                    if (itemId == 0) {
-                        final Context context = GeckoAppShell.getApplicationContext();
-                        if (type == GuestModeDialog.ENTERING) {
-                            GeckoProfile.enterGuestMode(context);
-                        } else {
-                            GeckoProfile.leaveGuestMode(context);
-                            // Now's a good time to make sure we're not displaying the
-                            // Guest Browsing notification.
-                            GuestSession.hideNotification(context);
-                        }
-                        doRestart();
-                    }
-                } catch (JSONException ex) {
-                    Log.e(LOGTAG, "Exception reading guest mode prompt result", ex);
+            public void onPromptFinished(final GeckoBundle result) {
+                final int itemId = result.getInt("button", -1);
+                if (itemId != 0) {
+                    return;
                 }
+
+                final Context context = GeckoAppShell.getApplicationContext();
+                if (type == GuestModeDialog.ENTERING) {
+                    GeckoProfile.enterGuestMode(context);
+                } else {
+                    GeckoProfile.leaveGuestMode(context);
+                    // Now's a good time to make sure we're not displaying the
+                    // Guest Browsing notification.
+                    GuestSession.hideNotification(context);
+                }
+                doRestart();
             }
         });
 
         Resources res = getResources();
         ps.setButtons(new String[] {
             res.getString(R.string.guest_session_dialog_continue),
             res.getString(R.string.guest_session_dialog_cancel)
         });
--- a/mobile/android/base/java/org/mozilla/gecko/delegates/BookmarkStateChangeDelegate.java
+++ b/mobile/android/base/java/org/mozilla/gecko/delegates/BookmarkStateChangeDelegate.java
@@ -30,16 +30,17 @@ import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.home.HomeConfig;
 import org.mozilla.gecko.promotion.SimpleHelperUI;
 import org.mozilla.gecko.prompts.Prompt;
 import org.mozilla.gecko.prompts.PromptListItem;
 import org.mozilla.gecko.util.DrawableUtil;
+import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import java.lang.ref.WeakReference;
 
 /**
  * Delegate to watch for bookmark state changes.
  *
  * This is responsible for showing snackbars and helper UIs related to the addition/removal
@@ -157,36 +158,32 @@ public class BookmarkStateChangeDelegate
                 .duration(Snackbar.LENGTH_LONG)
                 .buildAndShow();
     }
 
     private static void showBookmarkDialog(final BrowserApp browserApp) {
         final Resources res = browserApp.getResources();
         final Tab tab = Tabs.getInstance().getSelectedTab();
 
+        if (tab == null) {
+            return;
+        }
+
         final Prompt ps = new Prompt(browserApp, new Prompt.PromptCallback() {
             @Override
-            public void onPromptFinished(String result) {
-                int itemId = -1;
-                try {
-                    itemId = new JSONObject(result).getInt("button");
-                } catch (JSONException ex) {
-                    Log.e(LOGTAG, "Exception reading bookmark prompt result", ex);
-                }
-
-                if (tab == null) {
-                    return;
-                }
+            public void onPromptFinished(final GeckoBundle result) {
+                final int itemId = result.getInt("button", -1);
 
                 if (itemId == 0) {
                     final String extrasId = res.getResourceEntryName(R.string.contextmenu_edit_bookmark);
                     Telemetry.sendUIEvent(TelemetryContract.Event.ACTION,
                             TelemetryContract.Method.DIALOG, extrasId);
 
                     new EditBookmarkDialog(browserApp).show(tab.getURL());
+
                 } else if (itemId == 1) {
                     final String extrasId = res.getResourceEntryName(R.string.contextmenu_add_to_launcher);
                     Telemetry.sendUIEvent(TelemetryContract.Event.ACTION,
                             TelemetryContract.Method.DIALOG, extrasId);
 
                     final String url = tab.getURL();
                     final String title = tab.getDisplayTitle();
 
--- a/mobile/android/base/java/org/mozilla/gecko/prompts/IntentChooserPrompt.java
+++ b/mobile/android/base/java/org/mozilla/gecko/prompts/IntentChooserPrompt.java
@@ -1,29 +1,27 @@
 /* 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.prompts;
 
 import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.widget.GeckoActionProvider;
 
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.widget.ListView;
 import android.util.Log;
 
-import org.json.JSONException;
-import org.json.JSONObject;
-
 import java.util.ArrayList;
 import java.util.List;
 
 /**
  * Shows a prompt letting the user pick from a list of intent handlers for a set of Intents or
  * for a GeckoActionProvider.  Basic usage:
  *   IntentChooserPrompt prompt = new IntentChooserPrompt(context, new Intent[] {
  *      ... // some intents
@@ -61,27 +59,22 @@ public class IntentChooserPrompt {
         // If there's only one item in the intent list, just return it
         if (mItems.size() == 1) {
             handler.onIntentSelected(mItems.get(0).getIntent(), 0);
             return;
         }
 
         final Prompt prompt = new Prompt(context, new Prompt.PromptCallback() {
             @Override
-            public void onPromptFinished(String promptServiceResult) {
+            public void onPromptFinished(final GeckoBundle result) {
                 if (handler == null) {
                     return;
                 }
 
-                int itemId = -1;
-                try {
-                    itemId = new JSONObject(promptServiceResult).getInt("button");
-                } catch (JSONException e) {
-                    Log.e(LOGTAG, "result from promptservice was invalid: ", e);
-                }
+                final int itemId = result.getInt("button", -1);
 
                 if (itemId == -1) {
                     handler.onCancelled();
                 } else {
                     handler.onIntentSelected(mItems.get(itemId).getIntent(), itemId);
                 }
             }
         });
--- a/mobile/android/base/java/org/mozilla/gecko/prompts/Prompt.java
+++ b/mobile/android/base/java/org/mozilla/gecko/prompts/Prompt.java
@@ -1,18 +1,15 @@
 /* -*- 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.prompts;
 
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 
@@ -218,73 +215,81 @@ public class Prompt implements OnClickLi
         mInputs = inputs;
     }
 
     /* Adds to a result value from the lists that can be shown in dialogs.
      *  Will set the selected value(s) to the button attribute of the
      *  object that's passed in. If this is a multi-select dialog, sets a
      *  selected attribute to an array of booleans.
      */
-    private void addListResult(final JSONObject result, int which) {
+    private void addListResult(final GeckoBundle result, int which) {
         if (mAdapter == null) {
             return;
         }
 
-        try {
-            JSONArray selected = new JSONArray();
+        // If the button has already been filled in
+        final ArrayList<Integer> selected = mAdapter.getSelected();
 
-            // If the button has already been filled in
-            ArrayList<Integer> selectedItems = mAdapter.getSelected();
-            for (Integer item : selectedItems) {
-                selected.put(item);
+        // If we haven't assigned a button yet, or we assigned it to -1, assign the which
+        // parameter to both selected and the button.
+        if (result.getInt("button", -1) == -1) {
+            if (!selected.contains(which)) {
+                selected.add(which);
             }
 
-            // If we haven't assigned a button yet, or we assigned it to -1, assign the which
-            // parameter to both selected and the button.
-            if (!result.has("button") || result.optInt("button") == -1) {
-                if (!selectedItems.contains(which)) {
-                    selected.put(which);
-                }
+            result.putInt("button", which);
+        }
 
-                result.put("button", which);
-            }
-
-            result.put("list", selected);
-        } catch (JSONException ex) { }
+        result.putIntArray("list", selected);
     }
 
     /* Adds to a result value from the inputs that can be shown in dialogs.
      * Each input will set its own value in the result.
      */
-    private void addInputValues(final JSONObject result) {
-        try {
-            if (mInputs != null) {
-                for (int i = 0; i < mInputs.length; i++) {
-                    if (mInputs[i] != null) {
-                        result.put(mInputs[i].getId(), mInputs[i].getValue());
-                    }
-                }
+    private void addInputValues(final GeckoBundle result) {
+        if (mInputs == null) {
+            return;
+        }
+
+        for (final PromptInput input : mInputs) {
+            if (input == null) {
+                continue;
             }
-        } catch (JSONException ex) { }
+
+            final String id = input.getId();
+            final Object value = input.getValue();
+
+            if (value instanceof Boolean) {
+                result.putBoolean(id, (Boolean) value);
+            } else if (value instanceof Double) {
+                result.putDouble(id, (Double) value);
+            } else if (value instanceof Integer) {
+                result.putInt(id, (Integer) value);
+            } else if (value instanceof String) {
+                result.putString(id, (String) value);
+            } else if (value instanceof GeckoBundle) {
+                result.putBundle(id, (GeckoBundle) value);
+            } else {
+                throw new UnsupportedOperationException();
+            }
+        }
     }
 
     /* Adds the selected button to a result. This should only be called if there
      * are no lists shown on the dialog, since they also write their results to the button
      * attribute.
      */
-    private void addButtonResult(final JSONObject result, int which) {
+    private void addButtonResult(final GeckoBundle result, int which) {
         int button = -1;
         switch (which) {
             case DialogInterface.BUTTON_POSITIVE : button = 0; break;
             case DialogInterface.BUTTON_NEUTRAL  : button = 1; break;
             case DialogInterface.BUTTON_NEGATIVE : button = 2; break;
         }
-        try {
-            result.put("button", button);
-        } catch (JSONException ex) { }
+        result.putInt("button", button);
     }
 
     @Override
     public void onClick(DialogInterface dialog, int which) {
         ThreadUtils.assertOnUiThread();
         closeDialog(which);
     }
 
@@ -467,55 +472,52 @@ public class Prompt implements OnClickLi
      */
     @Override
     public void onCancel(DialogInterface aDialog) {
         ThreadUtils.assertOnUiThread();
         cancelDialog();
     }
 
     /* Called in situations where we want to cancel the dialog . This can happen if the user hits back,
-     * or if the dialog can't be created because of invalid JSON.
+     * or if the dialog can't be created because of invalid input.
      */
     private void cancelDialog() {
-        JSONObject ret = new JSONObject();
-        try {
-            ret.put("button", -1);
-        } catch (Exception ex) { }
+        final GeckoBundle ret = new GeckoBundle();
+        ret.putInt("button", -1);
         addInputValues(ret);
+
         notifyClosing(ret);
     }
 
     /* Called any time we're closing the dialog to cleanup and notify listeners that the dialog
      * is closing.
      */
     private void closeDialog(int which) {
-        JSONObject ret = new JSONObject();
+        final GeckoBundle ret = new GeckoBundle();
         mDialog.dismiss();
 
         addButtonResult(ret, which);
         addListResult(ret, which);
         addInputValues(ret);
 
         notifyClosing(ret);
     }
 
     /* Called any time we're closing the dialog to cleanup and notify listeners that the dialog
      * is closing.
      */
-    private void notifyClosing(JSONObject aReturn) {
-        try {
-            aReturn.put("guid", mGuid);
-        } catch (JSONException ex) { }
+    private void notifyClosing(final GeckoBundle ret) {
+        ret.putString("guid", mGuid);
 
         if (mTabId != Tabs.INVALID_TAB_ID) {
             Tabs.unregisterOnTabsChangedListener(this);
         }
 
         if (mCallback != null) {
-            mCallback.onPromptFinished(aReturn.toString());
+            mCallback.onPromptFinished(ret);
         }
     }
 
     // Called when the prompt inputs on the dialog change
     @Override
     public void onChange(PromptInput input) {
         // If there are no buttons on this dialog, assuming that "changing" an input
         // means something was selected and we can close. This provides a way to tap
@@ -533,16 +535,15 @@ public class Prompt implements OnClickLi
             closeDialog(mDoubleTapButtonType);
             return true;
         }
         mPreviousInputValue = inputValue;
         return false;
     }
 
     public interface PromptCallback {
-
         /**
          * Called when the Prompt has been completed (i.e. when the user has selected an item or action in the Prompt).
          * This callback is run on the UI thread.
          */
-        public void onPromptFinished(String jsonResult);
+        public void onPromptFinished(GeckoBundle result);
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/prompts/PromptService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/prompts/PromptService.java
@@ -36,15 +36,15 @@ public class PromptService implements Bu
 
     // BundleEventListener implementation
     @Override
     public void handleMessage(final String event, final GeckoBundle message,
                               final EventCallback callback) {
         Prompt p;
         p = new Prompt(mContext, new Prompt.PromptCallback() {
             @Override
-            public void onPromptFinished(String jsonResult) {
-                callback.sendSuccess(jsonResult);
+            public void onPromptFinished(final GeckoBundle result) {
+                callback.sendSuccess(result);
             }
         });
         p.show(message);
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/prompts/TabInput.java
+++ b/mobile/android/base/java/org/mozilla/gecko/prompts/TabInput.java
@@ -2,19 +2,16 @@
  * 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.prompts;
 
 import java.util.LinkedHashMap;
 
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.Context;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -23,17 +20,17 @@ import android.widget.AdapterView;
 import android.widget.ListView;
 import android.widget.TabHost;
 import android.widget.TextView;
 
 public class TabInput extends PromptInput implements AdapterView.OnItemClickListener {
     public static final String INPUT_TYPE = "tabs";
     public static final String LOGTAG = "GeckoTabInput";
 
-    /* Keeping the order of this in sync with the JSON is important. */
+    /* Keeping the order of this in sync with the input is important. */
     final private LinkedHashMap<String, PromptListItem[]> mTabs;
 
     private TabHost mHost;
     private int mPosition;
 
     public TabInput(GeckoBundle obj) {
         super(obj);
         mTabs = new LinkedHashMap<String, PromptListItem[]>();
@@ -70,22 +67,19 @@ public class TabInput extends PromptInpu
             mHost.addTab(spec);
         }
         mView = mHost;
         return mHost;
     }
 
     @Override
     public Object getValue() {
-        JSONObject obj = new JSONObject();
-        try {
-            obj.put("tab", mHost.getCurrentTab());
-            obj.put("item", mPosition);
-        } catch (JSONException ex) { }
-
+        final GeckoBundle obj = new GeckoBundle(2);
+        obj.putInt("tab", mHost.getCurrentTab());
+        obj.putInt("item", mPosition);
         return obj;
     }
 
     @Override
     public boolean getScrollable() {
         return true;
     }