Bug 1390735 - Support tint color for page action button. r?nechen,sebastian,walkingice draft
authorJing-wei Wu <topwu.tw@gmail.com>
Thu, 17 Aug 2017 09:33:43 +0800
changeset 648115 09f43f35fdbeaf0485dffc45ff62ea077f5e1e97
parent 648114 5e08c94ebc8ce74305220b08df065a0ec4ca9af7
child 648116 0a1b4859f8623910fd6e50c03d39b494af4a5f55
push id74628
push userbmo:topwu.tw@gmail.com
push dateThu, 17 Aug 2017 08:32:13 +0000
reviewersnechen, sebastian, walkingice
bugs1390735
milestone57.0a1
Bug 1390735 - Support tint color for page action button. r?nechen,sebastian,walkingice Use tint to provide two colors for page action icon in normal/private mode. We would not tint icons that already have their own colors(for example: ic_readermode_on.png or casting_active.png) or are came from 3-party addons. MozReview-Commit-ID: 8uuMucKGLw5
mobile/android/app/src/photon/res/color/page_action_fg.xml
mobile/android/base/java/org/mozilla/gecko/toolbar/PageActionLayout.java
mobile/android/chrome/content/CastingApps.js
mobile/android/chrome/content/Reader.js
mobile/android/chrome/content/browser.js
mobile/android/modules/PageActions.jsm
new file mode 100644
--- /dev/null
+++ b/mobile/android/app/src/photon/res/color/page_action_fg.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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/. -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          xmlns:gecko="http://schemas.android.com/apk/res-auto">
+
+    <item android:color="@color/menu_item_tint_private"
+          gecko:state_private="true"/>
+
+    <item android:color="@color/menu_item_tint"/>
+
+</selector>
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/PageActionLayout.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/PageActionLayout.java
@@ -2,28 +2,31 @@
  * 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.toolbar;
 
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.R;
+import org.mozilla.gecko.util.DrawableUtil;
 import org.mozilla.gecko.util.ResourceDrawableUtils;
 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.widget.GeckoPopupMenu;
 import org.mozilla.gecko.widget.themed.ThemedImageButton;
 import org.mozilla.gecko.widget.themed.ThemedLinearLayout;
 
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
+import android.support.v4.content.ContextCompat;
 import android.util.AttributeSet;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
@@ -103,18 +106,19 @@ public class PageActionLayout extends Th
                               final EventCallback callback) {
         ThreadUtils.assertOnUiThread();
 
         if ("PageActions:Add".equals(event)) {
             final String id = message.getString("id");
             final String title = message.getString("title");
             final String imageURL = message.getString("icon");
             final boolean important = message.getBoolean("important");
+            final boolean useTint = message.getBoolean("useTint");
 
-            addPageAction(id, title, imageURL, new OnPageActionClickListeners() {
+            addPageAction(id, title, imageURL, useTint, new OnPageActionClickListeners() {
                 @Override
                 public void onClick(final String id) {
                     final GeckoBundle data = new GeckoBundle(1);
                     data.putString("id", id);
                     EventDispatcher.getInstance().dispatch("PageActions:Clicked", data);
                 }
 
                 @Override
@@ -126,32 +130,37 @@ public class PageActionLayout extends Th
                 }
             }, important);
 
         } else if ("PageActions:Remove".equals(event)) {
             removePageAction(message.getString("id"));
         }
     }
 
-    private void addPageAction(final String id, final String title, final String imageData,
+    private void addPageAction(final String id, final String title, final String imageData, final boolean useTint,
             final OnPageActionClickListeners onPageActionClickListeners, boolean important) {
         ThreadUtils.assertOnUiThread();
 
         final PageAction pageAction = new PageAction(id, title, null, onPageActionClickListeners, important);
 
         int insertAt = mPageActionList.size();
         while (insertAt > 0 && mPageActionList.get(insertAt - 1).isImportant()) {
             insertAt--;
         }
         mPageActionList.add(insertAt, pageAction);
 
         ResourceDrawableUtils.getDrawable(mContext, imageData, new ResourceDrawableUtils.BitmapLoader() {
             @Override
-            public void onBitmapFound(final Drawable d) {
+            public void onBitmapFound(Drawable d) {
                 if (mPageActionList.contains(pageAction)) {
+                    if (useTint) {
+                        final ColorStateList colorStateList = ContextCompat.getColorStateList(
+                                getContext(), R.color.page_action_fg);
+                        d = DrawableUtil.tintDrawableWithStateList(d, colorStateList);
+                    }
                     pageAction.setDrawable(d);
                     refreshPageActionIcons();
                 }
             }
         });
     }
 
     private void removePageAction(String id) {
--- a/mobile/android/chrome/content/CastingApps.js
+++ b/mobile/android/chrome/content/CastingApps.js
@@ -553,24 +553,26 @@ var CastingApps = {
     // 1. The video is actively being cast
     // 2. The video is allowed to be cast and is currently playing
     // Both states have the same action: Show the cast page action
     if (aVideo.mozIsCasting) {
       this.pageAction.id = PageActions.add({
         title: Strings.browser.GetStringFromName("contextmenu.sendToDevice"),
         icon: "drawable://casting_active",
         clickCallback: this.pageAction.click,
-        important: true
+        important: true,
+        useTint: false
       });
     } else if (aVideo.mozAllowCasting) {
       this.pageAction.id = PageActions.add({
         title: Strings.browser.GetStringFromName("contextmenu.sendToDevice"),
         icon: "drawable://casting",
         clickCallback: this.pageAction.click,
-        important: true
+        important: true,
+        useTint: true
       });
     }
   },
 
   prompt: function(aWindow, aCallback, aFilterFunc) {
     let items = [];
     let filteredServices = [];
     SimpleServiceDiscovery.services.forEach(function(aService) {
--- a/mobile/android/chrome/content/Reader.js
+++ b/mobile/android/chrome/content/Reader.js
@@ -163,42 +163,43 @@ var Reader = {
       return;
     }
 
     if (this.pageAction.id) {
       PageActions.remove(this.pageAction.id);
       delete this.pageAction.id;
     }
 
-    let showPageAction = (icon, title) => {
+    let showPageAction = (icon, title, useTint) => {
       this.pageAction.id = PageActions.add({
         icon: icon,
         title: title,
         clickCallback: () => this.pageAction.readerModeCallback(browser),
-        important: true
+        important: true,
+        useTint: useTint
       });
     };
 
     let browser = tab.browser;
     if (browser.currentURI.spec.startsWith("about:reader")) {
-      showPageAction("drawable://ic_readermode_on", Strings.reader.GetStringFromName("readerView.close"));
+      showPageAction("drawable://ic_readermode_on", Strings.reader.GetStringFromName("readerView.close"), false);
       // Only start a reader session if the viewer is in the foreground. We do
       // not track background reader viewers.
       UITelemetry.startSession("reader.1", null);
       return;
     }
 
     // not in ReaderMode, to make sure System UI is visible, not dimmed.
     this._showSystemUI(true);
 
     // Only stop a reader session if the foreground viewer is not visible.
     UITelemetry.stopSession("reader.1", "", null);
 
     if (browser.isArticle) {
-      showPageAction("drawable://ic_readermode", Strings.reader.GetStringFromName("readerView.enter"));
+      showPageAction("drawable://ic_readermode", Strings.reader.GetStringFromName("readerView.enter"), true);
       UITelemetry.addEvent("show.1", "button", null, "reader_available");
       this._sendMmaEvent("reader_available");
     } else {
       UITelemetry.addEvent("show.1", "button", null, "reader_unavailable");
     }
   },
 
   _sendMmaEvent: function(event) {
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -6605,16 +6605,17 @@ var ExternalApps = {
     if (this._pageActionId != undefined)
       return;
 
     let mediaElement = this._getMediaContentElement(contentDocument);
 
     this._pageActionId = PageActions.add({
       title: Strings.browser.GetStringFromName("openInApp.pageAction"),
       icon: "drawable://icon_openinapp",
+      useTint: true,
 
       clickCallback: () => {
         UITelemetry.addEvent("launch.1", "pageaction", null, "helper");
 
         let wasPlaying = mediaElement && !mediaElement.paused && !mediaElement.ended;
         if (wasPlaying) {
           mediaElement.pause();
         }
--- a/mobile/android/modules/PageActions.jsm
+++ b/mobile/android/modules/PageActions.jsm
@@ -83,17 +83,18 @@ var PageActions = {
   add: function(aOptions) {
     let id = aOptions.id || uuidgen.generateUUID().toString()
 
     EventDispatcher.instance.sendRequest({
       type: "PageActions:Add",
       id: id,
       title: aOptions.title,
       icon: resolveGeckoURI(aOptions.icon),
-      important: "important" in aOptions ? aOptions.important : false
+      important: "important" in aOptions ? aOptions.important : false,
+      useTint: "useTint" in aOptions ? aOptions.useTint : false
     });
 
     this._items[id] = {};
 
     if (aOptions.clickCallback) {
       this._items[id].clickCallback = aOptions.clickCallback;
     }