Bug 1348718 - Build option menu button in same way draft
authorJulian_Chu <walkingice0204@gmail.com>
Fri, 07 Apr 2017 13:03:57 +0800
changeset 558825 a881457d4bf3364ddb2fdca0fee9cab94e8a9e17
parent 558824 646d32f2ac3d345be0c14c061880ea1bf1657ae5
child 558826 427d0a081e0a01c11a8c8d0e7f19e7eeccfad525
push id52957
push userbmo:walkingice0204@gmail.com
push dateSat, 08 Apr 2017 03:08:41 +0000
bugs1348718
milestone55.0a1
Bug 1348718 - Build option menu button in same way There might be up to 2 Always-show-as-action button in ActionBar. One for menu-options, one for 3rd-party app action-button, if any. According to our design spec, the two buttons appearance should be similiar, therefore now we create them by same method. MozReview-Commit-ID: GPVteQR3hxr
mobile/android/base/java/org/mozilla/gecko/customtabs/ActionBarPresenter.java
mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
mobile/android/base/resources/drawable-hdpi/ab_menu.png
mobile/android/base/resources/drawable-xhdpi/ab_menu.png
mobile/android/base/resources/values/dimens.xml
mobile/android/base/resources/values/styles.xml
mobile/android/tests/background/junit4/src/org/mozilla/gecko/customtabs/TestCustomTabsActivity.java
--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/ActionBarPresenter.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/ActionBarPresenter.java
@@ -11,22 +11,27 @@ import android.graphics.drawable.ColorDr
 import android.graphics.drawable.Drawable;
 import android.os.Build;
 import android.os.Handler;
 import android.support.annotation.ColorInt;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.UiThread;
 import android.support.v4.graphics.drawable.DrawableCompat;
+import android.support.v4.view.MenuItemCompat;
 import android.support.v7.app.ActionBar;
 import android.text.TextUtils;
+import android.view.Menu;
+import android.view.MenuItem;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowManager;
 import android.widget.ImageButton;
+import android.widget.ImageView;
 import android.widget.TextView;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.SiteIdentity;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.toolbar.SecurityModeUtil;
 import org.mozilla.gecko.toolbar.SiteIdentityPopup;
 import org.mozilla.gecko.util.ColorUtil;
@@ -104,16 +109,51 @@ public class ActionBarPresenter {
             public void run() {
                 updateCustomView(tab.getSiteIdentity(), title, url);
             }
         };
         mHandler.postDelayed(mUpdateAction, CUSTOM_VIEW_UPDATE_DELAY);
     }
 
     /**
+     * To add a always-show-as-action button to menu, and manually create a view to insert.
+     *
+     * @param menu the menu to insert new action-button.
+     * @param icon the image to be used for action-button.
+     * @param tint true if the icon should be tint by primary text color
+     * @return the view which be inserted to menu
+     */
+    public View addActionButton(@NonNull final Menu menu,
+                                @NonNull final Drawable icon,
+                                final boolean tint) {
+        final Resources res = mActionBar.getThemedContext().getResources();
+
+        // if we specify layout_width, layout_height in xml to build View, then add to ActionBar
+        // system might overwrite the value to WRAP_CONTENT.
+        // Therefore we create view manually to match design spec
+        final ImageButton btn = new ImageButton(mActionBar.getThemedContext(), null, 0);
+        final int size = res.getDimensionPixelSize(R.dimen.custom_tab_action_button_size);
+        final int padding = res.getDimensionPixelSize(R.dimen.custom_tab_action_button_padding);
+        btn.setPadding(padding, padding, padding, padding);
+        btn.setLayoutParams(new ViewGroup.LayoutParams(size, size));
+        btn.setScaleType(ImageView.ScaleType.FIT_CENTER);
+
+        if (tint) {
+            DrawableCompat.setTint(icon, mTextPrimaryColor);
+        }
+        btn.setImageDrawable(icon);
+
+        // menu id does not matter here. We can directly bind callback to the returned-view.
+        final MenuItem item = menu.add(Menu.NONE, -1, Menu.NONE, "");
+        item.setActionView(btn);
+        MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
+        return btn;
+    }
+
+    /**
      * Set background color to ActionBar, as well as Status bar.
      *
      * @param color  the color to apply to ActionBar
      * @param window Window instance for changing color status bar, or null if won't change it.
      */
     @UiThread
     public void setBackgroundColor(@ColorInt final int color,
                                    @Nullable final Window window) {
--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
@@ -11,51 +11,45 @@ import android.content.pm.PackageManager
 import android.content.pm.ResolveInfo;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.Browser;
-import android.support.annotation.ColorInt;
 import android.support.annotation.NonNull;
 import android.support.annotation.StyleRes;
-import android.support.annotation.VisibleForTesting;
 import android.support.design.widget.Snackbar;
-import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.util.SparseArrayCompat;
-import android.support.v4.view.MenuItemCompat;
 import android.support.v7.app.ActionBar;
 import android.support.v7.widget.Toolbar;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
-import android.view.ViewGroup.LayoutParams;
-import android.widget.ImageButton;
 import android.widget.ProgressBar;
 
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.SnackbarBuilder;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.menu.GeckoMenuInflater;
 import org.mozilla.gecko.util.Clipboard;
 import org.mozilla.gecko.util.ColorUtil;
+import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.IntentUtils;
 import org.mozilla.gecko.widget.GeckoPopupMenu;
-import org.mozilla.gecko.util.GeckoBundle;
 
 import java.util.List;
 
 public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedListener {
     private static final String LOGTAG = "CustomTabsActivity";
     private static final String SAVED_START_INTENT = "saved_intent_which_started_this_activity";
 
     private final SparseArrayCompat<PendingIntent> menuItemsIntent = new SparseArrayCompat<>();
@@ -213,50 +207,52 @@ public class CustomTabsActivity extends 
     }
 
     // Usually should use onCreateOptionsMenu() to initialize menu items. But GeckoApp overwrite
     // it to support custom menu(Bug 739412). Then the parameter *menu* in this.onCreateOptionsMenu()
     // and this.onPrepareOptionsMenu() are different instances - GeckoApp.onCreatePanelMenu() changed it.
     // CustomTabsActivity only use standard menu in ActionBar, so initialize menu here.
     @Override
     public boolean onCreatePanelMenu(final int id, final Menu menu) {
-        insertActionButton(menu, startIntent, actionBarPresenter.getTextPrimaryColor());
-
-        popupMenu = createCustomPopupMenu();
 
-        // Create a ImageButton manually, and use it as an anchor for PopupMenu.
-        final ImageButton btn = new ImageButton(getContext(),
-                null, 0, R.style.Widget_MenuButtonCustomTabs);
-        btn.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-        btn.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View anchor) {
-                popupMenu.setAnchor(anchor);
-                popupMenu.show();
-            }
-        });
+        // if 3rd-party app asks to add an action button
+        if (IntentUtil.hasActionButton(startIntent)) {
+            final Bitmap bitmap = IntentUtil.getActionButtonIcon(startIntent);
+            final Drawable icon = new BitmapDrawable(getResources(), bitmap);
+            final boolean shouldTint = IntentUtil.isActionButtonTinted(startIntent);
+            actionBarPresenter.addActionButton(menu, icon, shouldTint)
+                    .setOnClickListener(new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+                            onActionButtonClicked();
+                        }
+                    });
+        }
 
-        // Insert the anchor-button to Menu
-        final MenuItem item = menu.add(Menu.NONE, R.id.menu, Menu.NONE, "Menu Button");
-        item.setActionView(btn);
-        MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
+        // insert an action button for menu. click it to show popup menu
+        popupMenu = createCustomPopupMenu();
+        actionBarPresenter.addActionButton(menu, getDrawable(R.drawable.ab_menu), true)
+                .setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View anchor) {
+                        popupMenu.setAnchor(anchor);
+                        popupMenu.show();
+                    }
+                });
 
         updateMenuItemForward();
         return true;
     }
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case android.R.id.home:
                 finish();
                 return true;
-            case R.id.action_button:
-                onActionButtonClicked();
-                return true;
             case R.id.share:
                 onShareClicked();
                 return true;
             case R.id.custom_tabs_menu_forward:
                 onForwardClicked();
                 return true;
             case R.id.custom_tabs_menu_reload:
                 onReloadClicked();
@@ -270,47 +266,16 @@ public class CustomTabsActivity extends 
         if (intent != null) {
             performPendingIntent(intent);
             return true;
         }
 
         return super.onOptionsItemSelected(item);
     }
 
-    /**
-     * To insert a MenuItem (as an ActionButton) into Menu.
-     *
-     * @param menu   The options menu in which to place items.
-     * @param intent which to launch this activity
-     * @param tintColor color to tint action-button
-     * @return the MenuItem which be created and inserted into menu. Otherwise, null.
-     */
-    @VisibleForTesting
-    MenuItem insertActionButton(final Menu menu,
-                                final Intent intent,
-                                @ColorInt final int tintColor) {
-        if (!IntentUtil.hasActionButton(intent)) {
-            return null;
-        }
-
-        MenuItem item = menu.add(Menu.NONE,
-                R.id.action_button,
-                Menu.NONE,
-                IntentUtil.getActionButtonDescription(intent));
-        Bitmap bitmap = IntentUtil.getActionButtonIcon(intent);
-        final Drawable icon = new BitmapDrawable(getResources(), bitmap);
-        if (IntentUtil.isActionButtonTinted(intent)) {
-            DrawableCompat.setTint(icon, tintColor);
-        }
-        item.setIcon(icon);
-        MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
-
-        return item;
-    }
-
     private void bindNavigationCallback(@NonNull final Toolbar toolbar) {
         toolbar.setNavigationOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 final Tabs tabs = Tabs.getInstance();
                 final Tab tab = tabs.getSelectedTab();
                 tabs.closeTab(tab);
                 finish();
new file mode 100644
index 0000000000000000000000000000000000000000..2c7718576a4973bcc41af02af496d16528488363
GIT binary patch
literal 469
zc$@*%0V@89P)<h;3K|Lk000e1NJLTq001Na001Ni1^@s6;Q*MJ00004b3#c}2nYxW
zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^
zaAhuUa%Y?FJQ@H10a8gsK~z|U?U&6;13?gkYqYC1{-6O5>nj*f`kMZ{fdqU9iFpT?
zoQ=l>_24fm$V?J18wg<#oDNKo{h%+kY*Da7Z4XdW^UrV#@K_g-BLD~?+yMAqfM*)2
zdPwq)<fNLus<yHPBH5b>Go8}nY58OY$@|y??|lK_F~xMn5a=C1i0C5#AE~C6KwkhZ
zBYGRar@_}mgXF1*3`Ar=@&rI5SD2c=(5xmq`>J|9?I2a{04TDhA=#ZT#wt`YmSSv@
ze2REXy!U$mo>NRMJ@gyn)E6y*UYv8?dC@u70q|<@HBqQ)hvb;#SXHl(^H9&QTTRW<
zvqAD)M1~?VBzcCMKUb3N$i{eK@w61<CdoGdt8@Cud%uIkoygKd+mSG+w5?QAOP~h;
zy@*~Sai2D$sx6ZJne%h2ss|R&MO+luMC2I2B!o~R=S8umW*PYbm+@1A_T9QZ00000
LNkvXXu0mjfP4&a5
new file mode 100644
index 0000000000000000000000000000000000000000..4b21c1cc0bd91c8859f44ec68a31acb5a14d6fed
GIT binary patch
literal 660
zc$@*00&D$=P)<h;3K|Lk000e1NJLTq001xm001xu1^@s6R|5Hm00004b3#c}2nYxW
zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^
zaAhuUa%Y?FJQ@H10uf0>K~!jg?U~JL6hRb)Pj}ZjGbZ3pQ9&WdBnt_;6hYrZBH8)^
z;sdyFCn6}mg+H(06KHmde?b!$ZW3`!r+d1}O)Dcz&qTfDM5qsH)3@kzs`^q@eG5n=
z5{blLki~j&uh$!R?=J&Dp6Ac@_xE4N(z3>pd`Qxh3~g&jJ^)b6+uTef-5xXkOOtfV
zTF*L#7D#>uu+R}7)^&Xhz@C+0ZuKGnAUQy{c>q|HG_ce(9Y9eOUuFvC`L3m==>W>I
zd<S4-N|)zlS#DZtnhv1lI)HBzo)6pD;YZS{bM7(89g;iFxkr-D&D&QZF@b1jApnJ>
z6#%HJ>Lq|CqLwWr*Cl-#J3?$rx;AfL2ZH4Kl(W#9wVrhf6_P%N5Kc@Ah7h(#qtO`{
zrjzMLCTXS1JOE@_c1qH+rDlws_@5FZg+7E3PEHE8DRdfuw-U7e0u6whonm=@1BT|K
zA!*GyxAkN7an5Z?x*9_(_C~f0AXHWL3jf2*ClW@GJnx))N^-aTp?M-{b>6-Xgmdl^
z$>D^v(2(RsYd!N-h~x%<uGxN3*YyQUJ<|d7`~9V+Y2HrjQxwHgS(fjuG);HnrfH7O
z>f^ni+2?n#PN5@hX>qY5{<W^_<2bCPMF4wQmfh_NW?6OzhUQ~Yki6fP)W^%~_Yk4H
u9`l0ZtoQy3@biM>O)RZMB9Tb^G2a0mL!3nq&#y-S0000<MNUMnLSTX$s33X(
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -229,9 +229,13 @@
 
     <item name="activity_stream_base_margin" type="dimen">10dp</item>
     <item name="activity_stream_desired_tile_width" type="dimen">90dp</item>
     <item name="activity_stream_desired_tile_height" type="dimen">70dp</item>
     <item name="activity_stream_top_sites_text_height" type="dimen">30dp</item>
 
     <!-- Default touch target size for buttons/imageviews that might be of small size -->
     <item name="touch_target_size" type="dimen">48dp</item>
+
+    <!-- Custom tabs -->
+    <dimen name="custom_tab_action_button_size">56dp</dimen>
+    <dimen name="custom_tab_action_button_padding">16dp</dimen>
 </resources>
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -114,20 +114,16 @@
         <item name="android:drawablePadding">6dip</item>
         <item name="android:gravity">center_vertical</item>
         <item name="android:textAppearance">@style/TextAppearance</item>
         <item name="android:singleLine">true</item>
         <item name="android:ellipsize">middle</item>
         <item name="android:textSize">@dimen/menu_item_textsize</item>
     </style>
 
-    <style name="Widget.MenuButtonCustomTabs" parent="GeckoActionBar.Button.MenuButton">
-        <item name="android:tint">?android:textColorPrimary</item>
-    </style>
-
     <style name="Widget.MenuItemCustomTabs" parent="Widget.MenuItemDefault">
         <!-- In current design, there is only one style for Popup-menu, regardless of Dark/Light theme -->
         <item name="android:textColor">@android:color/black</item>
         <item name="android:textColorHighlight">?android:textColorHighlight</item>
         <item name="android:textColorHint">?android:attr/textColorHint</item>
         <item name="android:textColorLink">?android:attr/textColorLink</item>
     </style>
 
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/customtabs/TestCustomTabsActivity.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/customtabs/TestCustomTabsActivity.java
@@ -95,36 +95,9 @@ public class TestCustomTabsActivity {
         builder.setExitAnimations(spyContext, enterRes, exitRes);
         final Intent i = builder.build().intent;
 
         Whitebox.setInternalState(spyActivity, "usingCustomAnimation", true);
         Whitebox.setInternalState(spyActivity, "startIntent", i);
 
         Assert.assertEquals(THIRD_PARTY_PACKAGE_NAME, spyActivity.getPackageName());
     }
-
-    @Test
-    public void testInsertActionButton() {
-        // create properties for CustomTabsIntent
-        final String description = "Description";
-        final Intent actionIntent = new Intent(Intent.ACTION_VIEW);
-        final int reqCode = 0x123;
-        final PendingIntent pendingIntent = PendingIntent.getActivities(spyContext,
-                reqCode,
-                new Intent[]{actionIntent},
-                PendingIntent.FLAG_CANCEL_CURRENT);
-        final Bitmap bitmap = BitmapFactory.decodeResource(
-                spyContext.getResources(),
-                R.drawable.ic_action_settings); // arbitrary icon resource
-
-        // To create a CustomTabsIntent which is asking for ActionButton.
-        final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
-        builder.setActionButton(bitmap, description, pendingIntent, true);
-
-        // CustomTabsActivity should return a MenuItem with corresponding attributes.
-        Menu menu = new RoboMenu(spyContext);
-        MenuItem item = spyActivity.insertActionButton(menu, builder.build().intent, 0xFF0000);
-        Assert.assertNotNull(item);
-        Assert.assertEquals(item.getTitle(), description);
-        Assert.assertEquals(0, item.getOrder()); // should be the first one
-        Assert.assertTrue(item.isVisible());
-    }
 }
\ No newline at end of file