Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(986)

Unified Diff: chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java

Issue 156343002: Let AppBannerManager really create and manage banners (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Piling on more changes from Android UX requests Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java
index 4aa92215949f79398de65bd075f83915976c7a9d..1757c4da6ee683043d4f4515767cddc4e021413a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java
@@ -4,23 +4,46 @@
package org.chromium.chrome.browser.banners;
+import android.app.Activity;
+import android.content.ActivityNotFoundException;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.os.AsyncTask;
+import android.text.TextUtils;
+import android.util.Log;
+
+import org.chromium.base.CalledByNative;
import org.chromium.chrome.browser.EmptyTabObserver;
import org.chromium.chrome.browser.TabBase;
import org.chromium.chrome.browser.TabObserver;
import org.chromium.content.browser.ContentView;
import org.chromium.content_public.browser.WebContents;
+import org.chromium.ui.R;
+import org.chromium.ui.base.WindowAndroid;
+import org.chromium.ui.base.WindowAndroid.IntentCallback;
/**
* Manages an AppBannerView for a TabBase and its ContentView.
*
* The AppBannerManager manages a single AppBannerView, dismissing it when the user navigates to a
* new page or creating a new one when it detects that the current webpage is requesting a banner
- * to be built. The actual observeration of the WebContents (which triggers the automatic creation
+ * to be built. The actual observation of the WebContents (which triggers the automatic creation
* and removal of banners, among other things) is done by the native-side AppBannerManager.
*
- * This Java-side class owns its native-side counterpart.
+ * This Java-side class owns its native-side counterpart, which is basically used to grab resources
+ * from the network.
*/
-public class AppBannerManager {
+public class AppBannerManager implements AppBannerView.Observer, InstallerDelegate.Observer,
+ IntentCallback {
+ private static final String TAG = "AppBannerManager";
+
+ /** Retrieves information about a given package. */
+ private static DetailsDelegate sDetailsDelegate;
+
/** Pointer to the native side AppBannerManager. */
private final long mNativePointer;
@@ -30,6 +53,29 @@ public class AppBannerManager {
/** ContentView that the AppBannerView/AppBannerManager is currently attached to. */
private ContentView mContentView;
+ /** Current banner being shown. */
+ private AppBannerView mBannerView;
+
+ /** Data about the app being advertised. */
+ private AppData mAppData;
+
+ /**
+ * Checks if app banners are enabled.
+ * @return True if banners are enabled, false otherwise.
+ */
+ public static boolean isEnabled() {
+ return nativeIsEnabled();
+ }
+
+ /**
+ * Sets the delegate that provides information about a given package.
+ * @param delegate Delegate to use. Previously set ones are destroyed.
+ */
+ public static void setDetailsDelegate(DetailsDelegate delegate) {
+ if (sDetailsDelegate != null) sDetailsDelegate.destroy();
+ sDetailsDelegate = delegate;
+ }
+
/**
* Constructs an AppBannerManager for the given tab.
* @param tab Tab that the AppBannerManager will be attached to.
@@ -62,6 +108,7 @@ public class AppBannerManager {
@Override
public void onDestroyed(TabBase tab) {
nativeDestroy(mNativePointer);
+ resetState();
}
};
}
@@ -75,11 +122,166 @@ public class AppBannerManager {
}
/**
- * Checks if app banners are enabled.
- * @return True if banners are enabled, false otherwise.
+ * Grabs package information for the banner asynchronously.
+ * @param url URL for the page that is triggering the banner.
+ * @param packageName Name of the package that is being advertised.
*/
- public static boolean isEnabled() {
- return nativeIsEnabled();
+ @CalledByNative
+ private void prepareBanner(final String url, final String packageName) {
+ // Get rid of whatever banner is there currently.
+ if (mBannerView != null) {
+ dismissCurrentBanner();
+ mBannerView = null;
+ }
+
+ new AsyncTask<Void, Void, AppData>() {
+ @Override
+ protected AppData doInBackground(Void... args) {
+ // Ask the delegate to provide information about the package.
+ if (!isBannerForCurrentPage(url) || sDetailsDelegate == null) return null;
Yaron 2014/02/19 22:41:36 Hmm. I think these url-related calls should be on
gone 2014/02/20 22:07:24 Done.
+ AppData data = new AppData();
+ data.siteUrl = mContentView.getUrl();
Yaron 2014/02/19 22:41:36 Same point here. If you need this on bg thread, gr
gone 2014/02/20 22:07:24 Done.
+ int iconSize = AppBannerView.getIconSize(mContentView.getContext());
+ return sDetailsDelegate.getAppDetails(packageName, iconSize, data) ? data : null;
+ }
+
+ @Override
+ protected void onPostExecute(AppData result) {
+ // Start grabbing the icon for the app.
+ if (!isBannerForCurrentPage(url) || result == null) return;
+ mAppData = result;
+ nativeFetchIcon(mNativePointer, result.siteUrl, result.imageUrl);
+ return;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ /**
+ * Called when all the data required to show a banner has finally been retrieved.
+ * Creates the banner and shows it, as long as the banner is still meant for the current page.
+ * @param imageUrl URL of the icon.
+ * @param appIcon Bitmap containing the icon itself.
+ */
+ @CalledByNative
+ private void createBanner(String imageUrl, Bitmap appIcon) {
+ if (mAppData == null || !isBannerForCurrentPage(mAppData.siteUrl)
+ || !TextUtils.equals(mAppData.imageUrl, imageUrl)) {
+ return;
+ }
+
+ mAppData.icon = new BitmapDrawable(mContentView.getContext().getResources(), appIcon);
+ mBannerView = AppBannerView.create(mContentView, this, mAppData);
+ }
+
+ /**
+ * Dismisses whatever banner is currently being displayed.
+ * This is treated as an automatic dismissal and not one that blocks the banner from appearing
+ * in the future.
+ */
+ @CalledByNative
+ private void dismissCurrentBanner() {
+ if (mBannerView != null) mBannerView.dismiss();
+ resetState();
+ }
+
+ @Override
+ public void onButtonClicked(AppBannerView banner) {
+ if (mBannerView != banner) return;
+
+ if (mAppData.installState == AppData.INSTALL_STATE_NOT_INSTALLED) {
+ // The user initiated an install.
+ WindowAndroid window = mTabBase.getWindowAndroid();
+ if (window.showIntent(mAppData.installIntent, this, R.string.low_memory_error)) {
+ // Temporarily hide the banner.
+ mBannerView.createVerticalSnapAnimation(false);
+ } else {
+ Log.e(TAG, "Failed to fire install intent.");
+ dismissCurrentBanner();
+ }
+ } else if (mAppData.installState == AppData.INSTALL_STATE_INSTALLED) {
+ // The app is installed. Open it.
+ String packageName = mAppData.packageName;
+ PackageManager packageManager = mContentView.getContext().getPackageManager();
+ Intent appIntent = packageManager.getLaunchIntentForPackage(packageName);
+ try {
+ mContentView.getContext().startActivity(appIntent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "Failed to find app package: " + packageName);
+ }
+ dismissCurrentBanner();
+ }
+ }
+
+ @Override
+ public void onBannerClicked(AppBannerView banner) {
+ if (mContentView == null || mBannerView != banner) return;
+
+ try {
+ // Send the user to the app's Play store page.
+ IntentSender sender = banner.getAppData().detailsIntent.getIntentSender();
+ mContentView.getContext().startIntentSender(sender, new Intent(), 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ Log.e(TAG, "Failed to launch details intent.");
+ }
+
+ dismissCurrentBanner();
+ }
+
+ @Override
+ public void onIntentCompleted(WindowAndroid window, int resultCode,
+ ContentResolver contentResolver, Intent data) {
+ if (mContentView == null || mBannerView == null) return;
+
+ mBannerView.createVerticalSnapAnimation(true);
+ if (resultCode == Activity.RESULT_OK) {
+ // The user chose to install the app. Watch the PackageManager to see when it finishes
+ // installing it.
+ PackageManager packageManager = mContentView.getContext().getPackageManager();
+ mAppData.installTask =
+ new InstallerDelegate(packageManager, this, mAppData.packageName);
+ mAppData.installTask.start();
+ mAppData.installState = AppData.INSTALL_STATE_INSTALLING;
+ mBannerView.updateButtonState();
+ }
+ }
+
+ @Override
+ public void onInstallFinished(InstallerDelegate monitor, boolean success) {
+ if (mBannerView == null || mAppData.installTask != monitor) return;
+
+ if (success) {
+ // Let the user open the app from here.
+ mAppData.installState = AppData.INSTALL_STATE_INSTALLED;
+ mBannerView.updateButtonState();
+ } else {
+ dismissCurrentBanner();
+ }
+ }
+
+ @Override
+ public void onBannerDismissed(AppBannerView banner) {
+ if (mBannerView != banner) return;
+
+ // If the user swiped the banner off of the screen, block it from being shown again.
+ boolean swipedAway = Math.abs(banner.getTranslationX()) >= banner.getWidth();
+ if (swipedAway) nativeBlockBanner(mNativePointer, mAppData.siteUrl, mAppData.packageName);
+
+ resetState();
+ }
+
+ private void resetState() {
+ if (mAppData != null && mAppData.installTask != null) mAppData.installTask.cancel();
+ mBannerView = null;
+ mAppData = null;
+ }
+
+ /**
+ * Checks to see if the banner is for the currently displayed page.
+ * @param bannerUrl URL that requested a banner.
+ * @return True if the user is still on the same page.
+ */
+ private boolean isBannerForCurrentPage(String bannerUrl) {
+ return mContentView != null && TextUtils.equals(mContentView.getUrl(), bannerUrl);
}
private static native boolean nativeIsEnabled();
@@ -87,4 +289,7 @@ public class AppBannerManager {
private native void nativeDestroy(long nativeAppBannerManager);
private native void nativeReplaceWebContents(
long nativeAppBannerManager, WebContents webContents);
+ private native void nativeBlockBanner(
+ long nativeAppBannerManager, String url, String packageName);
+ private native void nativeFetchIcon(long nativeAppBannerManager, String url, String imageUrl);
}

Powered by Google App Engine
This is Rietveld 408576698