Bug 1393672 - Add a badge (at the same position of Page Actio) for PWA. r=jwu
authorNevin Chen(:nechen) <cnevinchen@gmail.com>
Tue, 26 Sep 2017 13:48:09 +0800
changeset 386275 b38a9374dabafc411db39a01ef050acf3120b7c5
parent 386274 521c3dd49ad33130d4cfe39acd20af9c7561a115
child 386276 385f9bbb4fd815828556ec0b99676c69f00c163e
push id53317
push usernechen@mozilla.com
push dateSat, 14 Oct 2017 13:24:28 +0000
treeherderautoland@385f9bbb4fd8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwu
bugs1393672
milestone58.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1393672 - Add a badge (at the same position of Page Actio) for PWA. r=jwu This bug is for the front end work to make users more engaged with PWA. Requirements 1. When the user goes to a web page that has manifest.json, we show a badge(in the same position of page action). 2. If the user switch to another normal page or other Java UI, the page action should be gone. 3. When the user see the PWA website for the first time, we will display a onboarding prompt to teach him how to add PWA to home screen. This prompt only shows once. MozReview-Commit-ID: AcyjHPVKg2b
mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
mobile/android/base/java/org/mozilla/gecko/Tab.java
mobile/android/base/java/org/mozilla/gecko/Tabs.java
mobile/android/base/java/org/mozilla/gecko/toolbar/PageActionLayout.java
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
@@ -504,16 +504,23 @@ public class GeckoApplication extends Ap
     public LightweightTheme getLightweightTheme() {
         return mLightweightTheme;
     }
 
     public void prepareLightweightTheme() {
         mLightweightTheme = new LightweightTheme(this);
     }
 
+    public static void createShortcut() {
+        final Tab selectedTab = Tabs.getInstance().getSelectedTab();
+        if (selectedTab != null) {
+            createShortcut(selectedTab.getTitle(), selectedTab.getURL());
+        }
+    }
+
     // Creates a homescreen shortcut for a web page.
     // This is the entry point from nsIShellService.
     @WrapForJNI(calledFrom = "gecko")
     public static void createShortcut(final String title, final String url) {
         final Tab selectedTab = Tabs.getInstance().getSelectedTab();
         final String manifestUrl = selectedTab.getManifestUrl();
 
         if (manifestUrl != null) {
--- a/mobile/android/base/java/org/mozilla/gecko/Tab.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Tab.java
@@ -18,16 +18,17 @@ import org.mozilla.gecko.gfx.BitmapUtils
 import org.mozilla.gecko.icons.IconCallback;
 import org.mozilla.gecko.icons.IconDescriptor;
 import org.mozilla.gecko.icons.IconRequestBuilder;
 import org.mozilla.gecko.icons.IconResponse;
 import org.mozilla.gecko.icons.Icons;
 import org.mozilla.gecko.reader.ReaderModeUtils;
 import org.mozilla.gecko.reader.ReadingListHelper;
 import org.mozilla.gecko.toolbar.BrowserToolbar.TabEditingState;
+import org.mozilla.gecko.toolbar.PageActionLayout;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.widget.SiteLogins;
 
 import android.content.ContentResolver;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
@@ -458,16 +459,26 @@ public class Tab {
     }
 
     public void setHasFeeds(boolean hasFeeds) {
         mHasFeeds = hasFeeds;
     }
 
     public void setManifestUrl(String manifestUrl) {
         mManifestUrl = manifestUrl;
+        updatePageAction();
+    }
+
+    public void updatePageAction() {
+        if (mManifestUrl != null) {
+            PageActionLayout.PageAction.showPwaPageAction();
+
+        } else {
+            PageActionLayout.PageAction.clearPwaPageAction();
+        }
     }
 
     public void setHasOpenSearch(boolean hasOpenSearch) {
         mHasOpenSearch = hasOpenSearch;
     }
 
     public void setLoadedFromCache(boolean loadedFromCache) {
         mLoadedFromCache = loadedFromCache;
--- a/mobile/android/base/java/org/mozilla/gecko/Tabs.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Tabs.java
@@ -305,16 +305,18 @@ public class Tabs implements BundleEvent
 
         // This avoids a NPE below, but callers need to be careful to
         // handle this case.
         if (tab == null || oldTab == tab) {
             return tab;
         }
 
         mSelectedTab = tab;
+        mSelectedTab.updatePageAction();
+
         notifyListeners(tab, TabEvents.SELECTED);
 
         if (mLayerView != null) {
             mLayerView.setClearColor(getTabColor(tab));
         }
 
         if (oldTab != null) {
             notifyListeners(oldTab, TabEvents.UNSELECTED);
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/PageActionLayout.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/PageActionLayout.java
@@ -1,16 +1,17 @@
 /* -*- 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.toolbar;
 
 import org.mozilla.gecko.EventDispatcher;
+import org.mozilla.gecko.GeckoApplication;
 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;
@@ -103,24 +104,33 @@ public class PageActionLayout extends Th
 
     @Override // BundleEventListener
     public void handleMessage(final String event, final GeckoBundle message,
                               final EventCallback callback) {
         ThreadUtils.assertOnUiThread();
 
         if ("PageActions:Add".equals(event)) {
             final String id = message.getString("id");
+
+            boolean alreadyAdded = isPwaAdded(id);
+            if (alreadyAdded) {
+                return;
+            }
             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, useTint, new OnPageActionClickListeners() {
                 @Override
                 public void onClick(final String id) {
+                    if (id != null && id.equals(PageAction.UUID_PAGE_ACTION_PWA)) {
+                        GeckoApplication.createShortcut();
+                        return;
+                    }
                     final GeckoBundle data = new GeckoBundle(1);
                     data.putString("id", id);
                     EventDispatcher.getInstance().dispatch("PageActions:Clicked", data);
                 }
 
                 @Override
                 public boolean onLongClick(String id) {
                     final GeckoBundle data = new GeckoBundle(1);
@@ -130,16 +140,25 @@ public class PageActionLayout extends Th
                 }
             }, important);
 
         } else if ("PageActions:Remove".equals(event)) {
             removePageAction(message.getString("id"));
         }
     }
 
+    private boolean isPwaAdded(String id) {
+        for (PageAction pageAction : mPageActionList) {
+            if (pageAction.getID() != null && pageAction.getID().equals(id)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     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()) {
@@ -323,17 +342,19 @@ public class PageActionLayout extends Th
         mPageActionsMenu.show();
     }
 
     private static interface OnPageActionClickListeners {
         public void onClick(String id);
         public boolean onLongClick(String id);
     }
 
-    private static class PageAction {
+    public static class PageAction {
+        public static final String UUID_PAGE_ACTION_PWA = "279c269d-6397-4f86-a6d2-452e26456d4a";
+
         private final OnPageActionClickListeners mOnPageActionClickListeners;
         private Drawable mDrawable;
         private final String mTitle;
         private final String mId;
         private final int key;
         private final boolean mImportant;
 
         public PageAction(String id,
@@ -345,16 +366,25 @@ public class PageActionLayout extends Th
             mTitle = title;
             mDrawable = image;
             mOnPageActionClickListeners = onPageActionClickListeners;
             mImportant = important;
 
             key = UUID.fromString(mId.subSequence(1, mId.length() - 2).toString()).hashCode();
         }
 
+        public static void showPwaPageAction() {
+            GeckoBundle bundle = new GeckoBundle();
+            bundle.putString("id", UUID_PAGE_ACTION_PWA);
+            bundle.putString("title", "Add PWA Shortcut");
+            bundle.putString("icon", "drawable://icon_openinapp");
+            bundle.putBoolean("important", true);
+            EventDispatcher.getInstance().dispatch("PageActions:Add", bundle);
+        }
+
         public Drawable getDrawable() {
             return mDrawable;
         }
 
         public void setDrawable(Drawable d) {
             mDrawable = d;
         }
 
@@ -381,10 +411,16 @@ public class PageActionLayout extends Th
         }
 
         public boolean onLongClick() {
             if (mOnPageActionClickListeners != null) {
                 return mOnPageActionClickListeners.onLongClick(mId);
             }
             return false;
         }
+
+        public static void clearPwaPageAction() {
+            GeckoBundle bundle = new GeckoBundle();
+            bundle.putString("id", UUID_PAGE_ACTION_PWA);
+            EventDispatcher.getInstance().dispatch("PageActions:Remove", bundle);
+        }
     }
 }