Bug 1352993 - Part 1, Generalize ActionModeCompat draft
authorJulian_Chu <walkingice0204@gmail.com>
Tue, 18 Apr 2017 15:26:53 +0800
changeset 564758 0147be0d4a541f503d596a369eeb7769cb7b0f52
parent 564757 8bac81ef2d4eee1f61a2786dc22dbdb20b48ebf2
child 564759 b2a825d28dd3c41cfb224af005846e6d9be3c7a1
push id54695
push userbmo:walkingice0204@gmail.com
push dateWed, 19 Apr 2017 02:43:31 +0000
bugs1352993
milestone55.0a1
Bug 1352993 - Part 1, Generalize ActionModeCompat We want to reuse ActionBarTextSelection in more activities, so remove custom classes from it, to make it easier to interactive with general Andorid classes. To achieve that * Let ActionModeCompat to be a subclass of ActionMode * Get rid of GeckoMenu BrowserApp is the only one consumer for ActionModeCompat, and it do understand the class type. We could move animateIn to it safely. After doing this, TextSelectionActionModeCallback could become a general ActionMode.Callback. MozReview-Commit-ID: 7FTwDTe1JYG
mobile/android/base/java/org/mozilla/gecko/ActionBarTextSelection.java
mobile/android/base/java/org/mozilla/gecko/ActionModeCompat.java
mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
--- a/mobile/android/base/java/org/mozilla/gecko/ActionBarTextSelection.java
+++ b/mobile/android/base/java/org/mozilla/gecko/ActionBarTextSelection.java
@@ -1,26 +1,26 @@
 /* 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.menu.GeckoMenu;
-import org.mozilla.gecko.menu.GeckoMenuItem;
 import org.mozilla.gecko.util.ResourceDrawableUtils;
 import org.mozilla.gecko.text.TextSelection;
 import org.mozilla.gecko.util.BundleEventListener;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.ActionModeCompat.Callback;
 
+import android.annotation.SuppressLint;
 import android.content.Context;
 import android.graphics.drawable.Drawable;
+import android.support.v7.view.ActionMode;
+import android.view.Menu;
 import android.view.MenuItem;
 
 import java.util.Arrays;
 import java.util.Timer;
 import java.util.TimerTask;
 
 import android.util.Log;
 
@@ -130,98 +130,92 @@ class ActionBarTextSelection implements 
             mCallback.updateItems(items);
             return;
         }
 
         if (context instanceof ActionModeCompat.Presenter) {
             final ActionModeCompat.Presenter presenter = (ActionModeCompat.Presenter) context;
             mCallback = new TextSelectionActionModeCallback(items);
             presenter.startActionModeCompat(mCallback);
-            mCallback.animateIn();
         }
     }
 
     private void endActionMode() {
         if (context instanceof ActionModeCompat.Presenter) {
             final ActionModeCompat.Presenter presenter = (ActionModeCompat.Presenter) context;
             presenter.endActionModeCompat();
         }
         mCurrentItems = null;
     }
 
-    private class TextSelectionActionModeCallback implements Callback {
+    private class TextSelectionActionModeCallback implements ActionMode.Callback {
         private GeckoBundle[] mItems;
-        private ActionModeCompat mActionMode;
+        private ActionMode mActionMode;
 
         public TextSelectionActionModeCallback(final GeckoBundle[] items) {
             mItems = items;
         }
 
         public void updateItems(final GeckoBundle[] items) {
             mItems = items;
             if (mActionMode != null) {
                 mActionMode.invalidate();
             }
         }
 
-        public void animateIn() {
-            if (mActionMode != null) {
-                mActionMode.animateIn();
-            }
-        }
-
+        @SuppressLint("AlwaysShowAction")
         @Override
-        public boolean onPrepareActionMode(final ActionModeCompat mode, final GeckoMenu menu) {
+        public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) {
             // Android would normally expect us to only update the state of menu items
             // here To make the js-java interaction a bit simpler, we just wipe out the
             // menu here and recreate all the javascript menu items in onPrepare instead.
             // This will be called any time invalidate() is called on the action mode.
             menu.clear();
 
             final int length = mItems.length;
             for (int i = 0; i < length; i++) {
                 final GeckoBundle obj = mItems[i];
-                final GeckoMenuItem menuitem = (GeckoMenuItem)
-                        menu.add(0, i, 0, obj.getString("label", ""));
-                final int actionEnum = obj.getBoolean("showAsAction") ?
-                        GeckoMenuItem.SHOW_AS_ACTION_ALWAYS : GeckoMenuItem.SHOW_AS_ACTION_NEVER;
-                menuitem.setShowAsAction(actionEnum, R.attr.menuItemActionModeStyle);
+                final MenuItem menuitem = menu.add(0, i, 0, obj.getString("label", ""));
+                final int actionEnum = obj.getBoolean("showAsAction")
+                        ? MenuItem.SHOW_AS_ACTION_ALWAYS
+                        : MenuItem.SHOW_AS_ACTION_NEVER;
+                menuitem.setShowAsAction(actionEnum);
 
                 final String iconString = obj.getString("icon", "");
                 ResourceDrawableUtils.getDrawable(context, iconString,
                         new ResourceDrawableUtils.BitmapLoader() {
                     @Override
                     public void onBitmapFound(Drawable d) {
                         if (d != null) {
                             menuitem.setIcon(d);
                         }
                     }
                 });
             }
             return true;
         }
 
         @Override
-        public boolean onCreateActionMode(ActionModeCompat mode, GeckoMenu unused) {
+        public boolean onCreateActionMode(ActionMode mode, Menu unused) {
             mActionMode = mode;
             return true;
         }
 
         @Override
-        public boolean onActionItemClicked(ActionModeCompat mode, MenuItem item) {
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
             final GeckoBundle obj = mItems[item.getItemId()];
             final GeckoBundle data = new GeckoBundle(1);
             data.putString("id", obj.getString("id", ""));
             GeckoApp.getEventDispatcher().dispatch("TextSelection:Action", data);
             return true;
         }
 
         // Called when the user exits the action mode
         @Override
-        public void onDestroyActionMode(ActionModeCompat mode) {
+        public void onDestroyActionMode(ActionMode mode) {
             mActionMode = null;
             mCallback = null;
 
             final GeckoBundle data = new GeckoBundle(1);
             data.putInt("selectionID", selectionID);
             GeckoApp.getEventDispatcher().dispatch("TextSelection:End", data);
         }
     }
--- a/mobile/android/base/java/org/mozilla/gecko/ActionModeCompat.java
+++ b/mobile/android/base/java/org/mozilla/gecko/ActionModeCompat.java
@@ -1,50 +1,34 @@
 /* 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 android.support.v7.view.ActionMode;
+import android.view.Gravity;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Toast;
+
 import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.menu.GeckoMenuItem;
 import org.mozilla.gecko.widget.GeckoPopupMenu;
 
-import android.view.Gravity;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.Toast;
-
-class ActionModeCompat implements GeckoPopupMenu.OnMenuItemClickListener,
-                                  GeckoPopupMenu.OnMenuItemLongClickListener,
-                                  View.OnClickListener {
+class ActionModeCompat extends ActionMode implements GeckoPopupMenu.OnMenuItemClickListener,
+        GeckoPopupMenu.OnMenuItemLongClickListener,
+        View.OnClickListener {
     private final String LOGTAG = "GeckoActionModeCompat";
 
     private final Callback mCallback;
     private final ActionModeCompatView mView;
     private final Presenter mPresenter;
 
-    /* A set of callbacks to be called during this ActionMode's lifecycle. These will control the
-     * creation, interaction with, and destruction of menuitems for the view */
-    public static interface Callback {
-        /* Called when action mode is first created. Implementors should use this to inflate menu resources. */
-        public boolean onCreateActionMode(ActionModeCompat mode, GeckoMenu menu);
-
-        /* Called to refresh an action mode's action menu. Called whenever the mode is invalidated. Implementors
-         * should use this to enable/disable/show/hide menu items. */
-        public boolean onPrepareActionMode(ActionModeCompat mode, GeckoMenu menu);
-
-        /* Called to report a user click on an action button. */
-        public boolean onActionItemClicked(ActionModeCompat mode, MenuItem item);
-
-        /* Called when an action mode is about to be exited and destroyed. */
-        public void onDestroyActionMode(ActionModeCompat mode);
-    }
-
     /* Presenters handle the actual showing/hiding of the action mode UI in the app. Its their responsibility
      * to create an action mode, and assign it Callbacks and ActionModeCompatView's. */
     public static interface Presenter {
         /* Called when an action mode should be shown */
         public void startActionModeCompat(final Callback callback);
 
         /* Called when whatever action mode is showing should be hidden */
         public void endActionModeCompat();
@@ -68,24 +52,55 @@ class ActionModeCompat implements GeckoP
             mCallback.onDestroyActionMode(this);
         }
     }
 
     public CharSequence getTitle() {
         return mView.getTitle();
     }
 
+    @Override
+    public CharSequence getSubtitle() {
+        throw new UnsupportedOperationException("This method is not supported by this class");
+    }
+
+    @Override
+    public View getCustomView() {
+        return mView;
+    }
+
+    @Override
+    public MenuInflater getMenuInflater() {
+        throw new UnsupportedOperationException("This method is not supported by this class");
+    }
+
     public void setTitle(CharSequence title) {
         mView.setTitle(title);
     }
 
     public void setTitle(int resId) {
         mView.setTitle(resId);
     }
 
+    @Override
+    public void setSubtitle(CharSequence subtitle) {
+        throw new UnsupportedOperationException("This method is not supported by this class");
+    }
+
+    @Override
+    public void setSubtitle(int resId) {
+        throw new UnsupportedOperationException("This method is not supported by this class");
+    }
+
+    @Override
+    public void setCustomView(View view) {
+        // ActionModeCompatView is custom view for this class
+        throw new UnsupportedOperationException("This method is not supported by this class");
+    }
+
     public GeckoMenu getMenu() {
         return mView.getMenu();
     }
 
     public void invalidate() {
         if (mCallback != null) {
             mCallback.onPrepareActionMode(this, mView.getMenu());
         }
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -4096,16 +4096,17 @@ public class BrowserApp extends GeckoApp
             // Otherwise, we're already showing an action mode. Just finish it and show the new one
             mActionMode.finish();
         }
 
         mActionMode = new ActionModeCompat(BrowserApp.this, callback, mActionBar);
         if (callback.onCreateActionMode(mActionMode, mActionMode.getMenu())) {
             mActionMode.invalidate();
         }
+        mActionMode.animateIn();
     }
 
     /* Implementing ActionModeCompat.Presenter */
     @Override
     public void endActionModeCompat() {
         if (mActionMode == null) {
             return;
         }