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

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: Upload error 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
« no previous file with comments | « no previous file | chrome/android/java/src/org/chromium/chrome/browser/banners/AppData.java » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..3071c85b30908978f9e40c5d568686d53dea8220 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,45 @@
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.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,
+ AppDetailsDelegate.Observer, IntentCallback {
+ private static final String TAG = "AppBannerManager";
+
+ /** Retrieves information about a given package. */
+ private static AppDetailsDelegate sAppDetailsDelegate;
+
/** Pointer to the native side AppBannerManager. */
private final long mNativePointer;
@@ -30,6 +52,32 @@ 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;
+
+ /** Task to get details about an app. */
+ private AppDetailsDelegate.DetailsTask mDetailsTask;
+
+ /**
+ * 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 setAppDetailsDelegate(AppDetailsDelegate delegate) {
+ if (sAppDetailsDelegate != null) sAppDetailsDelegate.destroy();
+ sAppDetailsDelegate = delegate;
+ }
+
/**
* Constructs an AppBannerManager for the given tab.
* @param tab Tab that the AppBannerManager will be attached to.
@@ -62,6 +110,7 @@ public class AppBannerManager {
@Override
public void onDestroyed(TabBase tab) {
nativeDestroy(mNativePointer);
+ resetState();
}
};
}
@@ -75,11 +124,177 @@ 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(String url, String packageName) {
+ // Get rid of whatever banner is there currently.
+ if (mBannerView != null) dismissCurrentBanner();
+
+ if (sAppDetailsDelegate == null || !isBannerForCurrentPage(url)) return;
+
+ mDetailsTask = sAppDetailsDelegate.createTask(
+ this, mContentView.getContext(), url, packageName);
+ mDetailsTask.execute();
+ }
+
+ /**
+ * Called when data about the package has been retrieved, which includes the url for the app's
+ * icon but not the icon Bitmap itself. Kicks off a background task to retrieve it.
+ * @param data Data about the app. Null if the task failed.
+ */
+ @Override
+ public void onAppDetailsRetrieved(AppData data) {
+ if (data == null || !isBannerForCurrentPage(data.siteUrl())) return;
+
+ mAppData = data;
+ String imageUrl = data.imageUrl();
+ if (TextUtils.isEmpty(imageUrl) || !nativeFetchIcon(mNativePointer, imageUrl)) resetState();
+ }
+
+ /**
+ * 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())) return;
+
+ if (!TextUtils.equals(mAppData.imageUrl(), imageUrl)) {
+ resetState();
+ return;
+ }
+
+ mAppData.setIcon(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 == 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 || mBannerView.getAppData() != mAppData) {
+ 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.
+ mAppData.beginTrackingInstallation(mContentView.getContext(), this);
+ mBannerView.updateButtonState();
+ }
+ }
+
+ @Override
+ public void onInstallFinished(InstallerDelegate monitor, boolean success) {
+ if (mBannerView == null || mAppData == null || mAppData.installTask() != monitor) return;
+
+ if (success) {
+ // Let the user open the app from here.
+ mAppData.setInstallState(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();
+ }
+
+ /**
+ * Resets all of the state, killing off any running tasks.
+ */
+ private void resetState() {
+ if (mDetailsTask != null) {
+ mDetailsTask.cancel(true);
+ mDetailsTask = null;
+ }
+
+ if (mAppData != null) {
+ mAppData.destroy();
+ mAppData = null;
+ }
+
+ mBannerView = 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 +302,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 boolean nativeFetchIcon(long nativeAppBannerManager, String imageUrl);
}
« no previous file with comments | « no previous file | chrome/android/java/src/org/chromium/chrome/browser/banners/AppData.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698