New WebApk Install UI [3/4]

This CL includes the following UI changes:
1) Add to homescreen from menu will show a dialog and won't trigger an infobar.
2) After user clicks "Add" button from the app banner, the banner
   disappears.
3) Show install-in-progress notification.

It also simplifies the existing logic:
1) Simplify the logic to show the dialog in AddToHomescreenManager and data
   fetcher.
3) Remove unnecessary logic for adding from menu in AppbanerInfobarDelegate.

Bug: 752338
Change-Id: Ie2a173f4bedb52382448a6a7fa383c2621dc7cc3
Reviewed-on: https://chromium-review.googlesource.com/611142
Commit-Queue: Xi Han <[email protected]>
Reviewed-by: Matthew Jones <[email protected]>
Reviewed-by: Ilya Sherman <[email protected]>
Reviewed-by: Dominick Ng <[email protected]>
Reviewed-by: Peter Kotwicz <[email protected]>
Reviewed-by: Yaron Friedman <[email protected]>
Cr-Commit-Position: refs/heads/master@{#496099}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
index 2dacfc3..6cba36787 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
@@ -191,9 +191,6 @@
     /** Switch for enabling "button only" swipe logic for Chrome Home. */
     public static final String CHROME_HOME_SWIPE_LOGIC_BUTTON_ONLY = "button-only";
 
-    /** Switch for enabling the new Install UI for WebAPKs. */
-    public static final String ENABLE_WEBAPK_NEW_INSTALL_UI = "enable-webapk-new-install-ui";
-
     // Prevent instantiation.
     private ChromeSwitches() {}
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/banners/InstallerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/banners/InstallerDelegate.java
index 29111c90..66882fa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/banners/InstallerDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/banners/InstallerDelegate.java
@@ -206,9 +206,7 @@
      * @param packageName Name of the package to check.
      */
     public @InstallState int determineInstallState(String packageName) {
-        if (mIsRunning || TextUtils.isEmpty(packageName)) {
-            // The package name being empty means we are installing a WebAPK, where we don't know
-            // what the package name is until installation is complete.
+        if (mIsRunning) {
             return INSTALL_STATE_INSTALLING;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java
index 74be983..d83a8a1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarAndroid.java
@@ -39,9 +39,6 @@
     // Data for web app installs.
     private final String mAppUrl;
 
-    // Indicates whether the infobar is for installing a WebAPK.
-    private boolean mIsWebApk;
-
     // Banner for native apps.
     private AppBannerInfoBarAndroid(String appTitle, Bitmap iconBitmap, AppData data) {
         super(0, iconBitmap, appTitle, null, data.installButtonText(), null);
@@ -52,13 +49,11 @@
     }
 
     // Banner for web apps.
-    private AppBannerInfoBarAndroid(String appTitle, Bitmap iconBitmap, String url,
-            boolean isWebApk) {
+    private AppBannerInfoBarAndroid(String appTitle, Bitmap iconBitmap, String url) {
         super(0, iconBitmap, appTitle, null, getAddToHomescreenText(), null);
         mAppTitle = appTitle;
         mAppData = null;
         mAppUrl = url;
-        mIsWebApk = isWebApk;
         mInstallState = InstallerDelegate.INSTALL_STATE_NOT_INSTALLED;
     }
 
@@ -137,24 +132,18 @@
     }
 
     private void updateButton() {
-        if (mButton == null || (mAppData == null && !mIsWebApk)) return;
+        if (mButton == null || mAppData == null) return;
 
         String text;
         String accessibilityText = null;
         boolean enabled = true;
         Context context = getContext();
         if (mInstallState == InstallerDelegate.INSTALL_STATE_NOT_INSTALLED) {
-            if (mIsWebApk) {
-                // If the installation of the WebAPK fails, the banner will disappear and
-                // a failure toast will be shown.
-                return;
-            }
             text = mAppData.installButtonText();
             accessibilityText = context.getString(
                     R.string.app_banner_view_native_app_install_accessibility, text);
         } else if (mInstallState == InstallerDelegate.INSTALL_STATE_INSTALLING) {
-            text = mIsWebApk ? context.getString(R.string.app_banner_installing_webapk)
-                    : context.getString(R.string.app_banner_installing);
+            text = context.getString(R.string.app_banner_installing);
             mButton.announceForAccessibility(text);
             enabled = false;
         } else {
@@ -183,8 +172,7 @@
     }
 
     @CalledByNative
-    private static InfoBar createWebAppInfoBar(String appTitle, Bitmap iconBitmap, String url,
-            boolean isWebApk) {
-        return new AppBannerInfoBarAndroid(appTitle, iconBitmap, url, isWebApk);
+    private static InfoBar createWebAppInfoBar(String appTitle, Bitmap iconBitmap, String url) {
+        return new AppBannerInfoBarAndroid(appTitle, iconBitmap, url);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegateAndroid.java
index 7ad31c0..ca2a40c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegateAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/infobar/AppBannerInfoBarDelegateAndroid.java
@@ -60,11 +60,6 @@
     }
 
     @CalledByNative
-    private void openApp(String packageName) {
-        mInstallerDelegate.openApp(packageName);
-    }
-
-    @CalledByNative
     private void showAppDetails(Tab tab, AppData appData) {
         tab.getWindowAndroid().showIntent(appData.detailsIntent(), null, null);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallService.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallService.java
new file mode 100644
index 0000000..6bda447
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallService.java
@@ -0,0 +1,88 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.webapps;
+
+import static android.content.Context.NOTIFICATION_SERVICE;
+
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder;
+import org.chromium.chrome.browser.notifications.NotificationBuilderFactory;
+import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions;
+import org.chromium.components.url_formatter.UrlFormatter;
+import org.chromium.webapk.lib.client.WebApkNavigationClient;
+
+/** Java counterpart to webapk_install_service.h. */
+public class WebApkInstallService {
+    /** Prefix used for generating a unique notification tag. */
+    private static final String WEBAPK_INSTALL_NOTIFICATION_TAG_PREFIX =
+            "webapk_install_notification_tag_prefix.";
+
+    /** We always use the same platform id for notifications. */
+    private static final int PLATFORM_ID = -1;
+
+    /** Displays a notification when a WebAPK is successfully installed. */
+    @CalledByNative
+    private static void showInstalledNotification(
+            String webApkPackage, String manifestUrl, String shortName, String url, Bitmap icon) {
+        Context context = ContextUtils.getApplicationContext();
+        Intent intent = WebApkNavigationClient.createLaunchWebApkIntent(webApkPackage, url, false
+                /* forceNavigation */);
+        PendingIntent clickPendingIntent =
+                PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+        showNotification(manifestUrl, shortName, url, icon,
+                context.getResources().getString(R.string.notification_webapk_installed),
+                clickPendingIntent);
+    }
+
+    /** Display a notification when an install starts. */
+    @CalledByNative
+    private static void showInstallInProgressNotification(
+            String manifestUrl, String shortName, String url, Bitmap icon) {
+        showNotification(manifestUrl, shortName, url, icon,
+                ContextUtils.getApplicationContext().getResources().getString(
+                        R.string.notification_webapk_install_in_progress, shortName),
+                null);
+    }
+
+    private static void showNotification(String notificationId, String shortName, String url,
+            Bitmap icon, String message, PendingIntent clickPendingIntent) {
+        Context context = ContextUtils.getApplicationContext();
+        ChromeNotificationBuilder notificationBuilder =
+                NotificationBuilderFactory.createChromeNotificationBuilder(
+                        false /* preferCompat */, ChannelDefinitions.CHANNEL_ID_BROWSER);
+        notificationBuilder.setContentTitle(shortName)
+                .setContentText(message)
+                .setLargeIcon(icon)
+                .setSmallIcon(R.drawable.ic_chrome)
+                .setContentIntent(clickPendingIntent)
+                .setWhen(System.currentTimeMillis())
+                .setSubText(UrlFormatter.formatUrlForSecurityDisplay(url, false /* showScheme */))
+                .setAutoCancel(true);
+
+        NotificationManager notificationManager =
+                (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
+        notificationManager.notify(WEBAPK_INSTALL_NOTIFICATION_TAG_PREFIX + notificationId,
+                PLATFORM_ID, notificationBuilder.build());
+    }
+
+    /** Cancels any ongoing notification for the WebAPK. */
+    @CalledByNative
+    private static void cancelNotification(String notificationId) {
+        NotificationManager notificationManager =
+                (NotificationManager) ContextUtils.getApplicationContext().getSystemService(
+                        NOTIFICATION_SERVICE);
+        notificationManager.cancel(
+                WEBAPK_INSTALL_NOTIFICATION_TAG_PREFIX + notificationId, PLATFORM_ID);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java
index 04c9e48..28da8f2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java
@@ -4,29 +4,15 @@
 
 package org.chromium.chrome.browser.webapps;
 
-import static android.content.Context.NOTIFICATION_SERVICE;
-
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 
 import org.chromium.base.Callback;
-import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
-import org.chromium.chrome.R;
 import org.chromium.chrome.browser.AppHooks;
-import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.banners.InstallerDelegate;
 import org.chromium.chrome.browser.metrics.WebApkUma;
-import org.chromium.chrome.browser.notifications.ChromeNotificationBuilder;
-import org.chromium.chrome.browser.notifications.NotificationBuilderFactory;
-import org.chromium.chrome.browser.notifications.channels.ChannelDefinitions;
-import org.chromium.components.url_formatter.UrlFormatter;
-import org.chromium.webapk.lib.client.WebApkNavigationClient;
 import org.chromium.webapk.lib.common.WebApkConstants;
 
 /**
@@ -93,12 +79,6 @@
                 WebApkInstaller.this.notify(result);
                 if (result == WebApkInstallResult.FAILURE) return;
 
-                if (result == WebApkInstallResult.SUCCESS
-                        && CommandLine.getInstance().hasSwitch(
-                                   ChromeSwitches.ENABLE_WEBAPK_NEW_INSTALL_UI)) {
-                    showInstallNotification(packageName, title, url, icon);
-                }
-
                 // Stores the source info of WebAPK in WebappDataStorage.
                 WebappRegistry.getInstance().register(
                         WebApkConstants.WEBAPK_ID_PREFIX + packageName,
@@ -120,34 +100,6 @@
         }
     }
 
-    /** Displays a notification that a WebAPK is successfully installed. */
-    private void showInstallNotification(
-            String webApkPackage, String title, String url, Bitmap icon) {
-        Context context = ContextUtils.getApplicationContext();
-
-        Intent intent = WebApkNavigationClient.createLaunchWebApkIntent(
-                webApkPackage, url, false /* forceNavigation */);
-        PendingIntent clickIntent =
-                PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
-
-        ChromeNotificationBuilder notificationBuilder =
-                NotificationBuilderFactory.createChromeNotificationBuilder(
-                        false /* preferCompat */, ChannelDefinitions.CHANNEL_ID_BROWSER);
-        notificationBuilder.setContentTitle(title)
-                .setContentText(
-                        context.getResources().getString(R.string.notification_webapk_installed))
-                .setLargeIcon(icon)
-                .setSmallIcon(R.drawable.ic_chrome)
-                .setContentIntent(clickIntent)
-                .setWhen(System.currentTimeMillis())
-                .setSubText(UrlFormatter.formatUrlForSecurityDisplay(url, false /* showScheme */))
-                .setAutoCancel(true);
-
-        NotificationManager notificationManager =
-                (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
-        notificationManager.notify(webApkPackage, 0, notificationBuilder.build());
-    }
-
     /**
      * Updates a WebAPK installation.
      * @param packageName The package name of the WebAPK to install.
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 62806fe2..734aca48 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1816,9 +1816,6 @@
       <message name="IDS_APP_BANNER_OPEN" desc="Text that indicates that clicking on the button will launch an application. [CHAR-LIMIT=25]">
         Open
       </message>
-      <message name="IDS_APP_BANNER_INSTALLING_WEBAPK" desc="Button text indicating that a WebAPK is being installed. [CHAR-LIMIT=25]">
-        Adding…
-      </message>
 
       <!-- App banner accessibility strings, used for touch exploration -->
       <message name="IDS_APP_BANNER_VIEW_NATIVE_APP_ACCESSIBILITY" desc="Accessibility text: Describes a prompt promoting the installation of an app related to the current page, including the app's name and its rating.">
@@ -1899,6 +1896,9 @@
       <message name="IDS_WEBAPK_INSTALL_IN_PROGRESS" desc="Indicates that an installation for the WebAPK for the specific website is already in progress.">
         Still adding previous site
       </message>
+      <message name="IDS_NOTIFICATION_WEBAPK_INSTALL_IN_PROGRESS" desc="Indicates that the install of a WebAPK is in progress.">
+        Installing <ph name="WEBAPK_NAME">%1$s<ex>Progressive Web Apps</ex></ph> ...
+      </message>
       <message name="IDS_NOTIFICATION_WEBAPK_INSTALLED" desc="Indicates that a WebAPK has been successfully installed.">
         Successfully installed.
       </message>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index b7f6f5e1..a181c9d07 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1212,6 +1212,7 @@
   "java/src/org/chromium/chrome/browser/webapps/WebApkDisclosureNotificationService.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkInfo.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java",
+  "java/src/org/chromium/chrome/browser/webapps/WebApkInstallService.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkManagedActivity.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkOfflineDialog.java",
   "java/src/org/chromium/chrome/browser/webapps/WebApkServiceClient.java",
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index a074611..6d8206ec 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4217,6 +4217,7 @@
       "../android/java/src/org/chromium/chrome/browser/util/UrlUtilities.java",
       "../android/java/src/org/chromium/chrome/browser/webapps/AddToHomescreenManager.java",
       "../android/java/src/org/chromium/chrome/browser/webapps/ChromeWebApkHost.java",
+      "../android/java/src/org/chromium/chrome/browser/webapps/WebApkInstallService.java",
       "../android/java/src/org/chromium/chrome/browser/webapps/WebApkInstaller.java",
       "../android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateDataFetcher.java",
       "../android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java",
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
index fa49776..74231f3 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.cc
@@ -8,12 +8,12 @@
 
 #include "base/android/jni_android.h"
 #include "base/android/jni_string.h"
-#include "base/location.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/android/shortcut_helper.h"
 #include "chrome/browser/android/shortcut_info.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/android/webapk/webapk_install_service.h"
+#include "chrome/browser/android/webapk/webapk_metrics.h"
 #include "chrome/browser/banners/app_banner_manager.h"
 #include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
@@ -44,8 +44,7 @@
     std::unique_ptr<ShortcutInfo> shortcut_info,
     const SkBitmap& primary_icon,
     const SkBitmap& badge_icon,
-    bool is_webapk,
-    webapk::InstallSource webapk_install_source) {
+    bool is_webapk) {
   DCHECK(shortcut_info);
   const GURL url = shortcut_info->url;
   if (url.is_empty())
@@ -54,25 +53,13 @@
   auto infobar_delegate =
       base::WrapUnique(new banners::AppBannerInfoBarDelegateAndroid(
           weak_manager, std::move(shortcut_info), primary_icon, badge_icon,
-          is_webapk, webapk_install_source));
-  auto* raw_delegate = infobar_delegate.get();
+          is_webapk));
   auto infobar = base::MakeUnique<AppBannerInfoBarAndroid>(
-      std::move(infobar_delegate), url, is_webapk);
+      std::move(infobar_delegate), url);
   if (!InfoBarService::FromWebContents(web_contents)
            ->AddInfoBar(std::move(infobar)))
     return false;
 
-  if (is_webapk) {
-    if (webapk_install_source == webapk::INSTALL_SOURCE_MENU) {
-      webapk::TrackInstallInfoBarShown(
-          webapk::WEBAPK_INFOBAR_SHOWN_FROM_MENU);
-      raw_delegate->Accept();
-    } else {
-      webapk::TrackInstallInfoBarShown(
-          webapk::WEBAPK_INFOBAR_SHOWN_FROM_BANNER);
-    }
-  }
-
   return true;
 }
 
@@ -92,21 +79,17 @@
 }
 
 AppBannerInfoBarDelegateAndroid::~AppBannerInfoBarDelegateAndroid() {
-  weak_ptr_factory_.InvalidateWeakPtrs();
-
   if (!has_user_interaction_) {
     if (!native_app_data_.is_null()) {
       TrackUserResponse(USER_RESPONSE_NATIVE_APP_IGNORED);
     } else {
-      if (TriggeredFromBanner())
-        TrackUserResponse(USER_RESPONSE_WEB_APP_IGNORED);
+      TrackUserResponse(USER_RESPONSE_WEB_APP_IGNORED);
       if (is_webapk_)
         webapk::TrackInstallEvent(webapk::INFOBAR_IGNORED);
     }
   }
 
-  if (TriggeredFromBanner())
-    TrackDismissEvent(DISMISS_EVENT_DISMISSED);
+  TrackDismissEvent(DISMISS_EVENT_DISMISSED);
   Java_AppBannerInfoBarDelegateAndroid_destroy(
       base::android::AttachCurrentThread(), java_delegate_);
   java_delegate_.Reset();
@@ -171,8 +154,7 @@
   content::WebContents* web_contents =
       InfoBarService::WebContentsFromInfoBar(infobar());
   if (!web_contents) {
-    if (TriggeredFromBanner())
-      TrackDismissEvent(DISMISS_EVENT_ERROR);
+    TrackDismissEvent(DISMISS_EVENT_ERROR);
     return true;
   }
 
@@ -190,18 +172,14 @@
     std::unique_ptr<ShortcutInfo> shortcut_info,
     const SkBitmap& primary_icon,
     const SkBitmap& badge_icon,
-    bool is_webapk,
-    webapk::InstallSource webapk_install_source)
+    bool is_webapk)
     : weak_manager_(weak_manager),
       app_title_(shortcut_info->name),
       shortcut_info_(std::move(shortcut_info)),
       primary_icon_(primary_icon),
       badge_icon_(badge_icon),
       has_user_interaction_(false),
-      is_webapk_(is_webapk),
-      install_state_(INSTALL_NOT_STARTED),
-      webapk_install_source_(webapk_install_source),
-      weak_ptr_factory_(this) {
+      is_webapk_(is_webapk) {
   CreateJavaDelegate();
 }
 
@@ -217,8 +195,7 @@
       package_name_(native_app_package_name),
       referrer_(referrer),
       has_user_interaction_(false),
-      is_webapk_(false),
-      weak_ptr_factory_(this) {
+      is_webapk_(false) {
   DCHECK(!native_app_data_.is_null());
   DCHECK(!package_name_.empty());
   CreateJavaDelegate();
@@ -269,64 +246,22 @@
 
 bool AppBannerInfoBarDelegateAndroid::AcceptWebApk(
     content::WebContents* web_contents) {
-  JNIEnv* env = base::android::AttachCurrentThread();
+  TrackUserResponse(USER_RESPONSE_WEB_APP_ACCEPTED);
+  AppBannerSettingsHelper::RecordBannerInstallEvent(
+      web_contents, shortcut_info_->url.spec(), AppBannerSettingsHelper::WEB);
 
-  // If the WebAPK is installed and the "Open" button is clicked, open the
-  // WebAPK. Do not send a BannerAccepted message.
-  if (install_state_ == INSTALLED) {
-    DCHECK(!package_name_.empty());
-    ScopedJavaLocalRef<jstring> jpackage_name(
-        ConvertUTF8ToJavaString(env, package_name_));
-    Java_AppBannerInfoBarDelegateAndroid_openApp(env, java_delegate_,
-                                                 jpackage_name);
-    webapk::TrackUserAction(webapk::USER_ACTION_INSTALLED_OPEN);
-    return true;
-  }
-
-  install_state_ = INSTALLING;
-  webapk::TrackInstallSource(webapk_install_source_);
-
-  if (TriggeredFromBanner()) {
-    TrackUserResponse(USER_RESPONSE_WEB_APP_ACCEPTED);
-    AppBannerSettingsHelper::RecordBannerInstallEvent(
-        web_contents, shortcut_info_->url.spec(), AppBannerSettingsHelper::WEB);
-  } else {
-    // This branch will be entered if we are a WebAPK that was triggered from
-    // the add to homescreen menu item. Manually record the app banner added to
-    // homescreen event in this case. Don't call
-    // AppBannerSettingsHelper::RecordBannerInstallEvent as that records
-    // banner-specific metrics in addition to this event.
-    AppBannerSettingsHelper::RecordBannerEvent(
-        web_contents, web_contents->GetLastCommittedURL(),
-        shortcut_info_->url.spec(),
-        AppBannerSettingsHelper::APP_BANNER_EVENT_DID_ADD_TO_HOMESCREEN,
-        AppBannerManager::GetCurrentTime());
-  }
-
-  UpdateInstallState(env, nullptr);
-  WebApkInstallService::FinishCallback callback =
-      base::Bind(&AppBannerInfoBarDelegateAndroid::OnWebApkInstallFinished,
-                 weak_ptr_factory_.GetWeakPtr());
-  ShortcutHelper::InstallWebApkWithSkBitmap(
-      web_contents, *shortcut_info_, primary_icon_, badge_icon_, callback);
-
+  WebApkInstallService::Get(web_contents->GetBrowserContext())
+      ->InstallAsync(web_contents, *shortcut_info_, primary_icon_, badge_icon_,
+                     webapk::INSTALL_SOURCE_BANNER);
   SendBannerAccepted();
-
-  // Prevent the infobar from disappearing, because the infobar will show
-  // "Adding" during the installation process.
-  return false;
-}
-
-bool AppBannerInfoBarDelegateAndroid::TriggeredFromBanner() const {
-  return !is_webapk_ || webapk_install_source_ == webapk::INSTALL_SOURCE_BANNER;
+  return true;
 }
 
 void AppBannerInfoBarDelegateAndroid::SendBannerAccepted() {
   if (!weak_manager_)
     return;
 
-  if (TriggeredFromBanner())
-    weak_manager_->SendBannerAccepted();
+  weak_manager_->SendBannerAccepted();
 
   // Send the appinstalled event. Note that this is fired *before* the
   // installation actually takes place (which can be a significant amount of
@@ -335,52 +270,6 @@
   weak_manager_->OnInstall();
 }
 
-void AppBannerInfoBarDelegateAndroid::OnWebApkInstallFinished(
-    WebApkInstallResult result,
-    bool relax_updates,
-    const std::string& webapk_package_name) {
-  if (result != WebApkInstallResult::SUCCESS) {
-    OnWebApkInstallFailed(result);
-    return;
-  }
-
-  install_state_ = INSTALLED;
-  package_name_ = webapk_package_name;
-  UpdateInstallState(base::android::AttachCurrentThread(), nullptr);
-}
-
-void AppBannerInfoBarDelegateAndroid::OnWebApkInstallFailed(
-    WebApkInstallResult result) {
-  if (!infobar())
-    return;
-
-  // If the install didn't definitely fail, we don't add a shortcut. This could
-  // happen if Play was busy with another install and this one is still queued
-  // (and hence might succeed in the future).
-  if (result == WebApkInstallResult::FAILURE) {
-    content::WebContents* web_contents =
-        InfoBarService::WebContentsFromInfoBar(infobar());
-    // Add webapp shortcut to the homescreen.
-    ShortcutHelper::AddToLauncherWithSkBitmap(web_contents, *shortcut_info_,
-                                              primary_icon_);
-  }
-
-  infobar()->RemoveSelf();
-}
-
-void AppBannerInfoBarDelegateAndroid::TrackWebApkInstallationDismissEvents(
-    InstallState install_state) {
-  if (install_state == INSTALL_NOT_STARTED) {
-    webapk::TrackInstallEvent(webapk::INFOBAR_DISMISSED_BEFORE_INSTALLATION);
-  } else if (install_state == INSTALLING) {
-    webapk::TrackInstallEvent(webapk::INFOBAR_DISMISSED_DURING_INSTALLATION);
-  } else if (install_state == INSTALLED) {
-    // If WebAPK is installed from this banner, TrackInstallEvent() is called in
-    // WebApkInstaller::OnResult().
-    webapk::TrackUserAction(webapk::USER_ACTION_INSTALLED_OPEN_DISMISS);
-  }
-}
-
 infobars::InfoBarDelegate::InfoBarIdentifier
 AppBannerInfoBarDelegateAndroid::GetIdentifier() const {
   return APP_BANNER_INFOBAR_DELEGATE_ANDROID;
@@ -396,18 +285,15 @@
   content::WebContents* web_contents =
       InfoBarService::WebContentsFromInfoBar(infobar());
 
-  if (weak_manager_ && TriggeredFromBanner())
+  if (weak_manager_)
     weak_manager_->SendBannerDismissed();
 
   if (native_app_data_.is_null()) {
     if (is_webapk_)
-      TrackWebApkInstallationDismissEvents(install_state_);
-    if (TriggeredFromBanner()) {
-      TrackUserResponse(USER_RESPONSE_WEB_APP_DISMISSED);
-      AppBannerSettingsHelper::RecordBannerDismissEvent(
-          web_contents, shortcut_info_->url.spec(),
-          AppBannerSettingsHelper::WEB);
-    }
+      webapk::TrackInstallEvent(webapk::INFOBAR_DISMISSED_BEFORE_INSTALLATION);
+    TrackUserResponse(USER_RESPONSE_WEB_APP_DISMISSED);
+    AppBannerSettingsHelper::RecordBannerDismissEvent(
+        web_contents, shortcut_info_->url.spec(), AppBannerSettingsHelper::WEB);
   } else {
     DCHECK(!package_name_.empty());
     TrackUserResponse(USER_RESPONSE_NATIVE_APP_DISMISSED);
diff --git a/chrome/browser/android/banners/app_banner_infobar_delegate_android.h b/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
index e7dd249..56e2e3e 100644
--- a/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
+++ b/chrome/browser/android/banners/app_banner_infobar_delegate_android.h
@@ -12,7 +12,6 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
-#include "chrome/browser/android/webapk/webapk_metrics.h"
 #include "components/infobars/core/confirm_infobar_delegate.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/image/image.h"
@@ -42,8 +41,7 @@
                      std::unique_ptr<ShortcutInfo> info,
                      const SkBitmap& primary_icon,
                      const SkBitmap& badge_icon,
-                     bool is_webapk,
-                     webapk::InstallSource webapk_install_source);
+                     bool is_webapk);
 
   // Creates an infobar and delegate for promoting the installation of an
   // Android app, and adds the infobar to the InfoBarManager for |web_contents|.
@@ -76,23 +74,12 @@
   bool Accept() override;
 
  private:
-  // The states of a WebAPK installation, where the infobar is displayed during
-  // the entire installation process. This state is used to correctly record
-  // UMA metrics.
-  enum InstallState {
-    INSTALL_NOT_STARTED,
-    INSTALLING,
-    INSTALLED,
-  };
-
   // Delegate for promoting a web app.
-  AppBannerInfoBarDelegateAndroid(
-      base::WeakPtr<AppBannerManager> weak_manager,
-      std::unique_ptr<ShortcutInfo> info,
-      const SkBitmap& primary_icon,
-      const SkBitmap& badge_icon,
-      bool is_webapk,
-      webapk::InstallSource webapk_install_source);
+  AppBannerInfoBarDelegateAndroid(base::WeakPtr<AppBannerManager> weak_manager,
+                                  std::unique_ptr<ShortcutInfo> info,
+                                  const SkBitmap& primary_icon,
+                                  const SkBitmap& badge_icon,
+                                  bool is_webapk);
 
   // Delegate for promoting an Android app.
   AppBannerInfoBarDelegateAndroid(
@@ -111,22 +98,10 @@
   // infobar should be closed as a result of the button press.
   bool AcceptWebApk(content::WebContents* web_contents);
 
-  // Returns false if this delegate is for a WebAPK and was triggered from the
-  // A2HS menu item. Otherwise returns true.
-  bool TriggeredFromBanner() const;
-
   // Called when the user accepts the banner to install the app. (Not called
   // when the "Open" button is pressed on the banner that is shown after
   // installation for WebAPK banners.)
   void SendBannerAccepted();
-  void OnWebApkInstallFinished(WebApkInstallResult result,
-                               bool relax_updates,
-                               const std::string& webapk_package_name);
-
-  // Called when a WebAPK install fails.
-  void OnWebApkInstallFailed(WebApkInstallResult result);
-
-  void TrackWebApkInstallationDismissEvents(InstallState install_state);
 
   // ConfirmInfoBarDelegate:
   infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
@@ -155,15 +130,6 @@
 
   bool is_webapk_;
 
-  // Indicates the current state of a WebAPK installation.
-  InstallState install_state_;
-
-  // Indicates the way in which a WebAPK (if applicable) is installed: from the
-  // menu or from an app banner.
-  webapk::InstallSource webapk_install_source_;
-
-  base::WeakPtrFactory<AppBannerInfoBarDelegateAndroid> weak_ptr_factory_;
-
   DISALLOW_COPY_AND_ASSIGN(AppBannerInfoBarDelegateAndroid);
 };
 
diff --git a/chrome/browser/android/banners/app_banner_manager_android.cc b/chrome/browser/android/banners/app_banner_manager_android.cc
index 75d5496..48455669 100644
--- a/chrome/browser/android/banners/app_banner_manager_android.cc
+++ b/chrome/browser/android/banners/app_banner_manager_android.cc
@@ -13,7 +13,6 @@
 #include "chrome/browser/android/banners/app_banner_infobar_delegate_android.h"
 #include "chrome/browser/android/shortcut_helper.h"
 #include "chrome/browser/android/webapk/chrome_webapk_host.h"
-#include "chrome/browser/android/webapk/webapk_metrics.h"
 #include "chrome/browser/android/webapk/webapk_web_manifest_checker.h"
 #include "chrome/browser/banners/app_banner_metrics.h"
 #include "chrome/browser/banners/app_banner_settings_helper.h"
@@ -247,8 +246,7 @@
             contents, GetWeakPtr(),
             CreateShortcutInfo(manifest_url_, manifest_, primary_icon_url_,
                                badge_icon_url_, can_install_webapk_),
-            primary_icon_, badge_icon_, can_install_webapk_,
-            webapk::INSTALL_SOURCE_BANNER)) {
+            primary_icon_, badge_icon_, can_install_webapk_)) {
       RecordDidShowBanner("AppBanner.WebApp.Shown");
       TrackDisplayEvent(DISPLAY_EVENT_WEB_APP_BANNER_CREATED);
       ReportStatus(contents, SHOWING_WEB_APP_BANNER);
diff --git a/chrome/browser/android/shortcut_helper.cc b/chrome/browser/android/shortcut_helper.cc
index 8a7b589..a0ac0a03 100644
--- a/chrome/browser/android/shortcut_helper.cc
+++ b/chrome/browser/android/shortcut_helper.cc
@@ -153,17 +153,6 @@
   AddShortcutWithSkBitmap(info, webapp_id, icon_bitmap);
 }
 
-// static
-void ShortcutHelper::InstallWebApkWithSkBitmap(
-    content::WebContents* web_contents,
-    const ShortcutInfo& info,
-    const SkBitmap& primary_icon_bitmap,
-    const SkBitmap& badge_icon_bitmap,
-    const WebApkInstallService::FinishCallback& callback) {
-  WebApkInstallService::Get(web_contents->GetBrowserContext())
-      ->InstallAsync(info, primary_icon_bitmap, badge_icon_bitmap, callback);
-}
-
 void ShortcutHelper::ShowWebApkInstallInProgressToast() {
   Java_ShortcutHelper_showWebApkInstallInProgressToast(
       base::android::AttachCurrentThread());
diff --git a/chrome/browser/android/shortcut_helper.h b/chrome/browser/android/shortcut_helper.h
index 8f4b966..05b847b 100644
--- a/chrome/browser/android/shortcut_helper.h
+++ b/chrome/browser/android/shortcut_helper.h
@@ -35,14 +35,6 @@
                                         const ShortcutInfo& info,
                                         const SkBitmap& icon_bitmap);
 
-  // Installs WebAPK and adds shortcut to the launcher.
-  static void InstallWebApkWithSkBitmap(
-      content::WebContents* web_contents,
-      const ShortcutInfo& info,
-      const SkBitmap& primary_icon_bitmap,
-      const SkBitmap& badge_icon_bitmap,
-      const WebApkInstallService::FinishCallback& callback);
-
   // Shows toast notifying user that a WebAPK install is already in progress
   // when user tries to queue a new install for the same WebAPK.
   static void ShowWebApkInstallInProgressToast();
diff --git a/chrome/browser/android/webapk/webapk_install_service.cc b/chrome/browser/android/webapk/webapk_install_service.cc
index 22dcbbea..e402a277 100644
--- a/chrome/browser/android/webapk/webapk_install_service.cc
+++ b/chrome/browser/android/webapk/webapk_install_service.cc
@@ -4,10 +4,16 @@
 
 #include "chrome/browser/android/webapk/webapk_install_service.h"
 
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
 #include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/android/shortcut_helper.h"
 #include "chrome/browser/android/shortcut_info.h"
 #include "chrome/browser/android/webapk/webapk_install_service_factory.h"
 #include "chrome/browser/android/webapk/webapk_installer.h"
+#include "jni/WebApkInstallService_jni.h"
+#include "ui/gfx/android/java_bitmap.h"
 
 // static
 WebApkInstallService* WebApkInstallService::Get(
@@ -26,19 +32,30 @@
   return installs_.count(web_manifest_url);
 }
 
-void WebApkInstallService::InstallAsync(const ShortcutInfo& shortcut_info,
+void WebApkInstallService::InstallAsync(content::WebContents* web_contents,
+                                        const ShortcutInfo& shortcut_info,
                                         const SkBitmap& primary_icon,
                                         const SkBitmap& badge_icon,
-                                        const FinishCallback& finish_callback) {
-  DCHECK(!IsInstallInProgress(shortcut_info.manifest_url));
+                                        webapk::InstallSource install_source) {
+  if (IsInstallInProgress(shortcut_info.manifest_url)) {
+    ShortcutHelper::ShowWebApkInstallInProgressToast();
+    return;
+  }
 
   installs_.insert(shortcut_info.manifest_url);
+  webapk::TrackInstallSource(install_source);
 
+  ShowInstallInProgressNotification(shortcut_info, primary_icon);
+
+  // We pass an observer which wraps the WebContents to the callback, since the
+  // installation may take more than 10 seconds so there is a chance that the
+  // WebContents has been destroyed before the install is finished.
+  auto observer = base::MakeUnique<LifetimeObserver>(web_contents);
   WebApkInstaller::InstallAsync(
       browser_context_, shortcut_info, primary_icon, badge_icon,
       base::Bind(&WebApkInstallService::OnFinishedInstall,
-                 weak_ptr_factory_.GetWeakPtr(), shortcut_info.manifest_url,
-                 finish_callback));
+                 weak_ptr_factory_.GetWeakPtr(), base::Passed(&observer),
+                 shortcut_info, primary_icon));
 }
 
 void WebApkInstallService::UpdateAsync(
@@ -53,11 +70,76 @@
 }
 
 void WebApkInstallService::OnFinishedInstall(
-    const GURL& web_manifest_url,
-    const FinishCallback& finish_callback,
+    std::unique_ptr<LifetimeObserver> observer,
+    const ShortcutInfo& shortcut_info,
+    const SkBitmap& primary_icon,
     WebApkInstallResult result,
     bool relax_updates,
     const std::string& webapk_package_name) {
-  finish_callback.Run(result, relax_updates, webapk_package_name);
-  installs_.erase(web_manifest_url);
+  installs_.erase(shortcut_info.manifest_url);
+
+  if (result == WebApkInstallResult::SUCCESS) {
+    ShowInstalledNotification(shortcut_info, primary_icon, webapk_package_name);
+    return;
+  }
+
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jstring> java_manifest_url =
+      base::android::ConvertUTF8ToJavaString(env,
+                                             shortcut_info.manifest_url.spec());
+  Java_WebApkInstallService_cancelNotification(env, java_manifest_url);
+
+  // If the install didn't definitely fail, we don't add a shortcut. This could
+  // happen if Play was busy with another install and this one is still queued
+  // (and hence might succeed in the future).
+  if (result == WebApkInstallResult::FAILURE) {
+    content::WebContents* web_contents = observer->web_contents();
+    if (!web_contents)
+      return;
+
+    ShortcutHelper::AddToLauncherWithSkBitmap(web_contents, shortcut_info,
+                                              primary_icon);
+  }
+}
+
+// static
+void WebApkInstallService::ShowInstallInProgressNotification(
+    const ShortcutInfo& shortcut_info,
+    const SkBitmap& primary_icon) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jstring> java_manifest_url =
+      base::android::ConvertUTF8ToJavaString(env,
+                                             shortcut_info.manifest_url.spec());
+  base::android::ScopedJavaLocalRef<jstring> java_short_name =
+      base::android::ConvertUTF16ToJavaString(env, shortcut_info.short_name);
+  base::android::ScopedJavaLocalRef<jstring> java_url =
+      base::android::ConvertUTF8ToJavaString(env, shortcut_info.url.spec());
+  base::android::ScopedJavaLocalRef<jobject> java_primary_icon =
+      gfx::ConvertToJavaBitmap(&primary_icon);
+
+  Java_WebApkInstallService_showInstallInProgressNotification(
+      env, java_manifest_url, java_short_name, java_url, java_primary_icon);
+}
+
+// static
+void WebApkInstallService::ShowInstalledNotification(
+    const ShortcutInfo& shortcut_info,
+    const SkBitmap& primary_icon,
+    const std::string& webapk_package_name) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  base::android::ScopedJavaLocalRef<jstring> java_webapk_package =
+      base::android::ConvertUTF8ToJavaString(env, webapk_package_name);
+  base::android::ScopedJavaLocalRef<jstring> java_manifest_url =
+      base::android::ConvertUTF8ToJavaString(env,
+                                             shortcut_info.manifest_url.spec());
+  base::android::ScopedJavaLocalRef<jstring> java_short_name =
+      base::android::ConvertUTF16ToJavaString(env, shortcut_info.short_name);
+  base::android::ScopedJavaLocalRef<jstring> java_url =
+      base::android::ConvertUTF8ToJavaString(env, shortcut_info.url.spec());
+  base::android::ScopedJavaLocalRef<jobject> java_primary_icon =
+      gfx::ConvertToJavaBitmap(&primary_icon);
+
+  Java_WebApkInstallService_showInstalledNotification(
+      env, java_webapk_package, java_manifest_url, java_short_name, java_url,
+      java_primary_icon);
 }
diff --git a/chrome/browser/android/webapk/webapk_install_service.h b/chrome/browser/android/webapk/webapk_install_service.h
index 6134f08b..520babf 100644
--- a/chrome/browser/android/webapk/webapk_install_service.h
+++ b/chrome/browser/android/webapk/webapk_install_service.h
@@ -15,11 +15,14 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
+#include "chrome/browser/android/webapk/webapk_metrics.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "url/gurl.h"
 
 namespace content {
 class BrowserContext;
+class WebContents;
 }
 
 struct ShortcutInfo;
@@ -57,13 +60,14 @@
   // Returns whether an install for |web_manifest_url| is in progress.
   bool IsInstallInProgress(const GURL& web_manifest_url);
 
-  // Talks to the Chrome WebAPK server to generate a WebAPK on the server and to
-  // Google Play to install the downloaded WebAPK. Calls |callback| once the
-  // install completed or failed.
-  void InstallAsync(const ShortcutInfo& shortcut_info,
+  // Installs WebAPK and adds shortcut to the launcher. It talks to the Chrome
+  // WebAPK server to generate a WebAPK on the server and to Google Play to
+  // install the downloaded WebAPK.
+  void InstallAsync(content::WebContents* web_contents,
+                    const ShortcutInfo& shortcut_info,
                     const SkBitmap& primary_icon,
                     const SkBitmap& badge_icon,
-                    const FinishCallback& finish_callback);
+                    webapk::InstallSource install_source);
 
   // Talks to the Chrome WebAPK server to update a WebAPK on the server and to
   // the Google Play server to install the downloaded WebAPK. Calls
@@ -75,13 +79,34 @@
                    const FinishCallback& finish_callback);
 
  private:
+  // Observes the lifetime of a WebContents.
+  class LifetimeObserver : public content::WebContentsObserver {
+   public:
+    explicit LifetimeObserver(content::WebContents* web_contents)
+        : WebContentsObserver(web_contents) {}
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(LifetimeObserver);
+  };
+
   // Called once the install/update completed or failed.
-  void OnFinishedInstall(const GURL& web_manifest_url,
-                         const FinishCallback& finish_callback,
+  void OnFinishedInstall(std::unique_ptr<LifetimeObserver> observer,
+                         const ShortcutInfo& shortcut_info,
+                         const SkBitmap& primary_icon,
                          WebApkInstallResult result,
                          bool relax_updates,
                          const std::string& webapk_package_name);
 
+  // Shows a notification that an install is in progress.
+  static void ShowInstallInProgressNotification(
+      const ShortcutInfo& shortcut_info,
+      const SkBitmap& primary_icon);
+
+  // Shows a notification that an install is completed.
+  static void ShowInstalledNotification(const ShortcutInfo& shortcut_info,
+                                        const SkBitmap& primary_icon,
+                                        const std::string& webapk_package_name);
+
   content::BrowserContext* browser_context_;
 
   // In progress installs.
diff --git a/chrome/browser/android/webapk/webapk_metrics.cc b/chrome/browser/android/webapk/webapk_metrics.cc
index f6c2b9c..a9c3c47 100644
--- a/chrome/browser/android/webapk/webapk_metrics.cc
+++ b/chrome/browser/android/webapk/webapk_metrics.cc
@@ -13,8 +13,6 @@
 const char kInstallDurationHistogram[] = "WebApk.Install.InstallDuration";
 const char kInstallEventHistogram[] = "WebApk.Install.InstallEvent";
 const char kInstallSourceHistogram[] = "WebApk.Install.InstallSource";
-const char kInfoBarShownHistogram[] = "WebApk.Install.InfoBarShown";
-const char kUserActionHistogram[] = "WebApk.Install.UserAction";
 
 void TrackRequestTokenDuration(base::TimeDelta delta) {
   UMA_HISTOGRAM_TIMES("WebApk.Install.RequestTokenDuration", delta);
@@ -32,13 +30,4 @@
   UMA_HISTOGRAM_ENUMERATION(kInstallSourceHistogram, event, INSTALL_SOURCE_MAX);
 }
 
-void TrackInstallInfoBarShown(InfoBarShown event) {
-  UMA_HISTOGRAM_ENUMERATION(kInfoBarShownHistogram, event,
-                            WEBAPK_INFOBAR_SHOWN_MAX);
-}
-
-void TrackUserAction(UserAction event) {
-  UMA_HISTOGRAM_ENUMERATION(kUserActionHistogram, event, USER_ACTION_MAX);
-}
-
 }  // namespace webapk
diff --git a/chrome/browser/android/webapk/webapk_metrics.h b/chrome/browser/android/webapk/webapk_metrics.h
index 7ddd37bf..c39bb340 100644
--- a/chrome/browser/android/webapk/webapk_metrics.h
+++ b/chrome/browser/android/webapk/webapk_metrics.h
@@ -35,31 +35,10 @@
   INSTALL_SOURCE_MAX,
 };
 
-// The ways in which the WebAPK infobar can be shown.
-enum InfoBarShown {
-  WEBAPK_INFOBAR_SHOWN_FROM_BANNER,
-  WEBAPK_INFOBAR_SHOWN_FROM_MENU,
-  WEBAPK_INFOBAR_SHOWN_MAX,
-};
-
-// User actions after a WebAPK is installed.
-enum UserAction {
-  // Launch a previously installed WebAPK since the WebAPK has been installed on
-  // the device before.
-  USER_ACTION_OPEN,  // Obsolete
-  USER_ACTION_OPEN_DISMISS,  // Obsolete
-  // Open a newly installed WebAPK via a successful installation.
-  USER_ACTION_INSTALLED_OPEN,
-  USER_ACTION_INSTALLED_OPEN_DISMISS,
-  USER_ACTION_MAX,
-};
-
 void TrackRequestTokenDuration(base::TimeDelta delta);
 void TrackInstallDuration(base::TimeDelta delta);
 void TrackInstallEvent(InstallEvent event);
 void TrackInstallSource(InstallSource event);
-void TrackInstallInfoBarShown(InfoBarShown event);
-void TrackUserAction(UserAction event);
 
 };  // namespace webapk
 
diff --git a/chrome/browser/android/webapps/add_to_homescreen_manager.cc b/chrome/browser/android/webapps/add_to_homescreen_manager.cc
index 648199f..64327ee 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_manager.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_manager.cc
@@ -11,7 +11,6 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/sequenced_worker_pool.h"
-#include "chrome/browser/android/banners/app_banner_infobar_delegate_android.h"
 #include "chrome/browser/android/banners/app_banner_manager_android.h"
 #include "chrome/browser/android/shortcut_helper.h"
 #include "chrome/browser/android/webapk/chrome_webapk_host.h"
@@ -73,23 +72,17 @@
 
   RecordAddToHomescreen();
   if (is_webapk_compatible_) {
-    WebApkInstallService* install_service =
-        WebApkInstallService::Get(web_contents->GetBrowserContext());
-    if (install_service->IsInstallInProgress(
-            data_fetcher_->shortcut_info().manifest_url)) {
-      ShortcutHelper::ShowWebApkInstallInProgressToast();
-    } else {
-      CreateInfoBarForWebApk(data_fetcher_->shortcut_info(),
-                             data_fetcher_->primary_icon(),
-                             data_fetcher_->badge_icon());
-    }
-    return;
+    WebApkInstallService::Get(web_contents->GetBrowserContext())
+        ->InstallAsync(web_contents, data_fetcher_->shortcut_info(),
+                       data_fetcher_->primary_icon(),
+                       data_fetcher_->badge_icon(),
+                       webapk::INSTALL_SOURCE_MENU);
+  } else {
+    ShortcutHelper::AddToLauncherWithSkBitmap(web_contents,
+                                              data_fetcher_->shortcut_info(),
+                                              data_fetcher_->primary_icon());
   }
 
-  ShortcutHelper::AddToLauncherWithSkBitmap(web_contents,
-                                            data_fetcher_->shortcut_info(),
-                                            data_fetcher_->primary_icon());
-
   // Fire the appinstalled event.
   banners::AppBannerManagerAndroid* app_banner_manager =
       banners::AppBannerManagerAndroid::FromWebContents(web_contents);
@@ -159,16 +152,3 @@
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_AddToHomescreenManager_onReadyToAdd(env, java_ref_, java_bitmap);
 }
-
-void AddToHomescreenManager::CreateInfoBarForWebApk(
-    const ShortcutInfo& info,
-    const SkBitmap& primary_icon,
-    const SkBitmap& badge_icon) {
-  content::WebContents* web_contents = data_fetcher_->web_contents();
-  banners::AppBannerManagerAndroid* app_banner_manager =
-      banners::AppBannerManagerAndroid::FromWebContents(web_contents);
-  banners::AppBannerInfoBarDelegateAndroid::Create(
-      web_contents, app_banner_manager->GetWeakPtr(),
-      base::MakeUnique<ShortcutInfo>(info), primary_icon, badge_icon,
-      true /* is_webapk */, webapk::INSTALL_SOURCE_MENU);
-}
diff --git a/chrome/browser/android/webapps/add_to_homescreen_manager.h b/chrome/browser/android/webapps/add_to_homescreen_manager.h
index fe28b36..1222b5a 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_manager.h
+++ b/chrome/browser/android/webapps/add_to_homescreen_manager.h
@@ -41,12 +41,6 @@
  private:
   ~AddToHomescreenManager() override;
 
-  // Called only when the AddToHomescreenDataFetcher has retrieved all of the
-  // data needed to install a WebAPK.
-  void CreateInfoBarForWebApk(const ShortcutInfo& info,
-                              const SkBitmap& primary_icon,
-                              const SkBitmap& badge_icon);
-
   void RecordAddToHomescreen();
 
   // AddToHomescreenDataFetcher::Observer:
diff --git a/chrome/browser/ui/android/infobars/app_banner_infobar_android.cc b/chrome/browser/ui/android/infobars/app_banner_infobar_android.cc
index cf9e853..2d558e9 100644
--- a/chrome/browser/ui/android/infobars/app_banner_infobar_android.cc
+++ b/chrome/browser/ui/android/infobars/app_banner_infobar_android.cc
@@ -22,11 +22,8 @@
 
 AppBannerInfoBarAndroid::AppBannerInfoBarAndroid(
     std::unique_ptr<banners::AppBannerInfoBarDelegateAndroid> delegate,
-    const GURL& app_url,
-    bool is_webapk)
-    : ConfirmInfoBar(std::move(delegate)),
-    app_url_(app_url),
-    is_webapk_(is_webapk) {}
+    const GURL& app_url)
+    : ConfirmInfoBar(std::move(delegate)), app_url_(app_url) {}
 
 AppBannerInfoBarAndroid::~AppBannerInfoBarAndroid() {
 }
@@ -60,7 +57,7 @@
         base::android::ConvertUTF8ToJavaString(env, trimmed_url);
 
     infobar.Reset(Java_AppBannerInfoBarAndroid_createWebAppInfoBar(
-        env, app_title, java_bitmap, app_url, is_webapk_));
+        env, app_title, java_bitmap, app_url));
   }
 
   java_infobar_.Reset(env, infobar.obj());
diff --git a/chrome/browser/ui/android/infobars/app_banner_infobar_android.h b/chrome/browser/ui/android/infobars/app_banner_infobar_android.h
index 0ace22c..9c8e3eb 100644
--- a/chrome/browser/ui/android/infobars/app_banner_infobar_android.h
+++ b/chrome/browser/ui/android/infobars/app_banner_infobar_android.h
@@ -25,8 +25,7 @@
   // Constructs an AppBannerInfoBarAndroid promoting a web app.
   AppBannerInfoBarAndroid(
       std::unique_ptr<banners::AppBannerInfoBarDelegateAndroid> delegate,
-      const GURL& app_url,
-      bool is_webapk);
+      const GURL& app_url);
 
   ~AppBannerInfoBarAndroid() override;
 
@@ -46,9 +45,6 @@
   // Web app: URL for the app.
   GURL app_url_;
 
-  // Indicates whether the info bar is for installing a WebAPK.
-  bool is_webapk_;
-
   base::android::ScopedJavaGlobalRef<jobject> java_infobar_;
 
   DISALLOW_COPY_AND_ASSIGN(AppBannerInfoBarAndroid);
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 0264076..0738f0c 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -39375,6 +39375,9 @@
 </enum>
 
 <enum name="WebApkInstallInfoBarShown">
+  <obsolete>
+    Deprecated as of 8/2017
+  </obsolete>
   <int value="0" label="WebApk infobar shown from the app banner"/>
   <int value="1" label="WebApk infobar shown from the add to homescreen menu"/>
 </enum>
@@ -39403,6 +39406,9 @@
 </enum>
 
 <enum name="WebApkUserAction">
+  <obsolete>
+    Deprecated as of 8/2017.
+  </obsolete>
   <int value="0" label="Open a previously installed WebAPK"/>
   <int value="1" label="Dismiss to open a previously installed WebAPK"/>
   <int value="2" label="Open a newly installed WebAPK"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index c4dbbf5..52f1de8 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -86292,6 +86292,9 @@
 </histogram>
 
 <histogram name="WebApk.Install.InfoBarShown" enum="WebApkInstallInfoBarShown">
+  <obsolete>
+    Deprecated 2017-08. As of M62, this is no longer recorded.
+  </obsolete>
   <owner>[email protected]</owner>
   <owner>[email protected]</owner>
   <owner>[email protected]</owner>
@@ -86353,6 +86356,9 @@
 </histogram>
 
 <histogram name="WebApk.Install.UserAction" enum="WebApkUserAction">
+  <obsolete>
+    Deprecated 2017-08. As of M62, this is no longer recorded.
+  </obsolete>
   <owner>[email protected]</owner>
   <owner>[email protected]</owner>
   <owner>[email protected]</owner>