Commit 534f316d authored by dfalcantara's avatar dfalcantara Committed by Commit bot

Start showing basic infobars for manifest apps

* Create a new skeleton InfoBarDelegate for app banners containing
  information about apps defined by web manifests.

* Displays an infobar when the user navigates to a page
  with a manifest.

* Adds a string for "Add to homescreen" for the new infobar.

BUG=453170

Review URL: https://codereview.chromium.org/893073002

Cr-Commit-Position: refs/heads/master@{#314273}
parent a80419dc
...@@ -115,6 +115,11 @@ public class AppBannerManager implements AppBannerView.Observer, AppDetailsDeleg ...@@ -115,6 +115,11 @@ public class AppBannerManager implements AppBannerView.Observer, AppDetailsDeleg
nativeReplaceWebContents(mNativePointer, mTab.getWebContents()); nativeReplaceWebContents(mNativePointer, mTab.getWebContents());
} }
@CalledByNative
private int getPreferredIconSize() {
return AppBannerView.getIconSize(mContentViewCore.getContext());
}
/** /**
* Grabs package information for the banner asynchronously. * Grabs package information for the banner asynchronously.
* @param url URL for the page that is triggering the banner. * @param url URL for the page that is triggering the banner.
...@@ -127,7 +132,7 @@ public class AppBannerManager implements AppBannerView.Observer, AppDetailsDeleg ...@@ -127,7 +132,7 @@ public class AppBannerManager implements AppBannerView.Observer, AppDetailsDeleg
if (sAppDetailsDelegate == null || !isBannerForCurrentPage(url)) return; if (sAppDetailsDelegate == null || !isBannerForCurrentPage(url)) return;
int iconSize = AppBannerView.getIconSize(mContentViewCore.getContext()); int iconSize = getPreferredIconSize();
sAppDetailsDelegate.getAppDetailsAsynchronously(this, url, packageName, iconSize); sAppDetailsDelegate.getAppDetailsAsynchronously(this, url, packageName, iconSize);
} }
...@@ -225,8 +230,8 @@ public class AppBannerManager implements AppBannerView.Observer, AppDetailsDeleg ...@@ -225,8 +230,8 @@ public class AppBannerManager implements AppBannerView.Observer, AppDetailsDeleg
* @return True if the user is still on the same page. * @return True if the user is still on the same page.
*/ */
private boolean isBannerForCurrentPage(String bannerUrl) { private boolean isBannerForCurrentPage(String bannerUrl) {
return mContentViewCore != null && return mContentViewCore != null
TextUtils.equals(mContentViewCore.getWebContents().getUrl(), bannerUrl); && TextUtils.equals(mContentViewCore.getWebContents().getUrl(), bannerUrl);
} }
private static native boolean nativeIsEnabled(); private static native boolean nativeIsEnabled();
......
...@@ -15001,13 +15001,16 @@ Do you accept? ...@@ -15001,13 +15001,16 @@ Do you accept?
If enabled, EmbeddedSearch API will be used to submit search queries in the search results page. If enabled, EmbeddedSearch API will be used to submit search queries in the search results page.
</message> </message>
<!-- App install alerts flags --> <!-- App install alerts strings -->
<message name="IDS_FLAGS_ENABLE_APP_INSTALL_ALERTS_NAME" desc="Title for the flag to allow app install alerts"> <message name="IDS_FLAGS_ENABLE_APP_INSTALL_ALERTS_NAME" desc="Title for the flag to allow app install alerts">
Enable app install alerts Enable app install alerts
</message> </message>
<message name="IDS_FLAGS_ENABLE_APP_INSTALL_ALERTS_DESCRIPTION" desc="Description to allow app install alerts"> <message name="IDS_FLAGS_ENABLE_APP_INSTALL_ALERTS_DESCRIPTION" desc="Description to allow app install alerts">
If enabled, websites will be parsed for app install alert meta tags. If enabled, websites will be parsed for app install alert meta tags.
</message> </message>
<message name="IDS_APP_INSTALL_ALERTS_ADD_TO_HOMESCREEN" desc="Infobar button text indicating that an app can be added to the home screen.">
Add to homescreen
</message>
<!-- Flag strings for seccomp-bpf sandbox flag. --> <!-- Flag strings for seccomp-bpf sandbox flag. -->
<message name="IDS_FLAGS_ENABLE_SECCOMP_FILTER_SANDBOX_ANDROID_NAME" desc="Title for the flag to enable the seccomp-bpf sandbox on Android."> <message name="IDS_FLAGS_ENABLE_SECCOMP_FILTER_SANDBOX_ANDROID_NAME" desc="Title for the flag to enable the seccomp-bpf sandbox on Android.">
......
// Copyright 2015 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.
#include "chrome/browser/android/banners/app_banner_infobar_delegate.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/grit/generated_resources.h"
#include "components/infobars/core/infobar.h"
#include "ui/base/l10n/l10n_util.h"
namespace banners {
infobars::InfoBar* AppBannerInfoBarDelegate::CreateForWebApp(
InfoBarService* infobar_service,
const AppDelegate* helper,
const base::string16& app_name,
const GURL& url) {
AppBannerInfoBarDelegate* const delegate = new AppBannerInfoBarDelegate(
helper,
app_name,
url);
return infobar_service->AddInfoBar(infobar_service->CreateConfirmInfoBar(
scoped_ptr<ConfirmInfoBarDelegate>(delegate)));
}
AppBannerInfoBarDelegate::AppBannerInfoBarDelegate(
const AppDelegate* helper,
const base::string16& app_title,
const GURL& url)
: delegate_(helper),
app_title_(app_title),
url_(url),
button_text_(l10n_util::GetStringUTF16(
IDS_APP_INSTALL_ALERTS_ADD_TO_HOMESCREEN)) {
}
AppBannerInfoBarDelegate::~AppBannerInfoBarDelegate() {
}
base::string16 AppBannerInfoBarDelegate::GetMessageText() const {
return app_title_;
}
int AppBannerInfoBarDelegate::GetButtons() const {
return BUTTON_OK;
}
base::string16 AppBannerInfoBarDelegate::GetButtonLabel(InfoBarButton button)
const {
return button_text_;
}
gfx::Image AppBannerInfoBarDelegate::GetIcon() const {
DCHECK(delegate_);
return delegate_->GetIcon();
}
void AppBannerInfoBarDelegate::InfoBarDismissed() {
DCHECK(delegate_);
delegate_->Block();
}
bool AppBannerInfoBarDelegate::Accept() {
DCHECK(delegate_);
delegate_->Install();
return true;
}
} // namespace banners
// Copyright 2015 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.
#ifndef CHROME_BROWSER_ANDROID_BANNERS_APP_BANNER_INFOBAR_DELEGATE_H_
#define CHROME_BROWSER_ANDROID_BANNERS_APP_BANNER_INFOBAR_DELEGATE_H_
#include "base/strings/string16.h"
#include "components/infobars/core/confirm_infobar_delegate.h"
#include "ui/gfx/image/image.h"
#include "url/gurl.h"
class InfoBarService;
namespace banners {
// Displays information about an app being promoted by a webpage.
class AppBannerInfoBarDelegate : public ConfirmInfoBarDelegate {
public:
// Handles calls dealing with blocking, promoting, or grabbing info about an
// app.
class AppDelegate {
public:
// User has elected to block the banner from being displayed.
virtual void Block() const = 0;
// User has requested that the app be installed.
virtual void Install() const = 0;
// Icon to display for the app.
virtual gfx::Image GetIcon() const = 0;
};
// Creates a banner for the current page.
// May return nullptr if the the infobar couldn't be created.
static infobars::InfoBar* CreateForWebApp(InfoBarService* infobar_service,
const AppDelegate* helper,
const base::string16& app_title,
const GURL& url);
// Changes the label of the button.
void SetButtonLabel(const std::string& button_text);
// InfoBarDelegate overrides.
gfx::Image GetIcon() const override;
void InfoBarDismissed() override;
// ConfirmInfoBarDelegate overrides.
base::string16 GetMessageText() const override;
int GetButtons() const override;
base::string16 GetButtonLabel(InfoBarButton button) const override;
bool Accept() override;
private:
// Constructor for a banner for web apps.
AppBannerInfoBarDelegate(const AppDelegate* helper,
const base::string16& app_title,
const GURL& url);
~AppBannerInfoBarDelegate() override;
const AppDelegate* delegate_;
base::string16 app_title_;
GURL url_;
base::string16 button_text_;
DISALLOW_COPY_AND_ASSIGN(AppBannerInfoBarDelegate);
}; // AppBannerInfoBarDelegate
} // namespace banners
#endif // CHROME_BROWSER_ANDROID_BANNERS_APP_BANNER_INFOBAR_DELEGATE_H_
...@@ -9,10 +9,12 @@ ...@@ -9,10 +9,12 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/metrics/histogram.h" #include "base/metrics/histogram.h"
#include "chrome/browser/android/banners/app_banner_infobar_delegate.h"
#include "chrome/browser/android/banners/app_banner_metrics_ids.h" #include "chrome/browser/android/banners/app_banner_metrics_ids.h"
#include "chrome/browser/android/banners/app_banner_utilities.h" #include "chrome/browser/android/banners/app_banner_utilities.h"
#include "chrome/browser/banners/app_banner_settings_helper.h" #include "chrome/browser/banners/app_banner_settings_helper.h"
#include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h" #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
...@@ -29,6 +31,7 @@ ...@@ -29,6 +31,7 @@
using base::android::ConvertJavaStringToUTF8; using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF8ToJavaString; using base::android::ConvertUTF8ToJavaString;
using base::android::ConvertUTF16ToJavaString;
namespace { namespace {
const char kBannerTag[] = "google-play-id"; const char kBannerTag[] = "google-play-id";
...@@ -58,6 +61,28 @@ void AppBannerManager::BlockBanner(JNIEnv* env, ...@@ -58,6 +61,28 @@ void AppBannerManager::BlockBanner(JNIEnv* env,
AppBannerSettingsHelper::Block(web_contents(), url, package_name); AppBannerSettingsHelper::Block(web_contents(), url, package_name);
} }
void AppBannerManager::Block() const {
if (!web_contents() || manifest_.IsEmpty())
return;
AppBannerSettingsHelper::Block(web_contents(),
web_contents()->GetURL(),
manifest_.start_url.spec());
}
void AppBannerManager::Install() const {
if (!web_contents())
return;
if (!manifest_.IsEmpty()) {
// TODO(dfalcantara): Trigger shortcut creation.
}
}
gfx::Image AppBannerManager::GetIcon() const {
return gfx::Image::CreateFrom1xBitmap(*app_icon_.get());
}
void AppBannerManager::ReplaceWebContents(JNIEnv* env, void AppBannerManager::ReplaceWebContents(JNIEnv* env,
jobject obj, jobject obj,
jobject jweb_contents) { jobject jweb_contents) {
...@@ -69,6 +94,11 @@ void AppBannerManager::ReplaceWebContents(JNIEnv* env, ...@@ -69,6 +94,11 @@ void AppBannerManager::ReplaceWebContents(JNIEnv* env,
void AppBannerManager::DidNavigateMainFrame( void AppBannerManager::DidNavigateMainFrame(
const content::LoadCommittedDetails& details, const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) { const content::FrameNavigateParams& params) {
// Clear current state.
fetcher_.reset();
manifest_ = content::Manifest();
app_icon_.reset();
// Get rid of the current banner. // Get rid of the current banner.
JNIEnv* env = base::android::AttachCurrentThread(); JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> jobj = weak_java_banner_view_manager_.get(env); ScopedJavaLocalRef<jobject> jobj = weak_java_banner_view_manager_.get(env);
...@@ -105,7 +135,23 @@ void AppBannerManager::OnDidGetManifest(const content::Manifest& manifest) { ...@@ -105,7 +135,23 @@ void AppBannerManager::OnDidGetManifest(const content::Manifest& manifest) {
// TODO(benwells): Check triggering parameters here and if there is a meta // TODO(benwells): Check triggering parameters here and if there is a meta
// tag. // tag.
// TODO(dfalcantara): Show banner for web site with manifest.
// Create an infobar to promote the manifest's app.
manifest_ = manifest;
/* TODO(dfalcantara): Use after landing https://crrev.com/880203004.
GURL icon_url =
ManifestIconSelector::FindBestMatchingIcon(manifest.icons,
GetPreferredIconSize(),
web_contents());
if (icon_url.is_empty())
return;
*/
if (manifest.icons.empty())
return;
GURL icon_url = manifest.icons.back().src;
FetchIcon(icon_url);
} }
bool AppBannerManager::OnMessageReceived(const IPC::Message& message) { bool AppBannerManager::OnMessageReceived(const IPC::Message& message) {
...@@ -126,13 +172,26 @@ void AppBannerManager::OnFetchComplete(const GURL url, const SkBitmap* bitmap) { ...@@ -126,13 +172,26 @@ void AppBannerManager::OnFetchComplete(const GURL url, const SkBitmap* bitmap) {
if (jobj.is_null()) if (jobj.is_null())
return; return;
ScopedJavaLocalRef<jstring> jimage_url( bool displayed;
ConvertUTF8ToJavaString(env, url.spec())); if (manifest_.IsEmpty()) {
ScopedJavaLocalRef<jobject> jimage = gfx::ConvertToJavaBitmap(bitmap); ScopedJavaLocalRef<jobject> jimage = gfx::ConvertToJavaBitmap(bitmap);
bool displayed = Java_AppBannerManager_createBanner(env, ScopedJavaLocalRef<jstring> jimage_url(
jobj.obj(), ConvertUTF8ToJavaString(env, url.spec()));
jimage_url.obj(),
jimage.obj()); displayed = Java_AppBannerManager_createBanner(env,
jobj.obj(),
jimage_url.obj(),
jimage.obj());
} else {
app_icon_.reset(new SkBitmap(*bitmap));
InfoBarService* service = InfoBarService::FromWebContents(web_contents());
displayed = AppBannerInfoBarDelegate::CreateForWebApp(
service,
this,
manifest_.name.string(),
manifest_.start_url) != NULL;
}
if (displayed) if (displayed)
banners::TrackDisplayEvent(DISPLAY_CREATED); banners::TrackDisplayEvent(DISPLAY_CREATED);
} else { } else {
...@@ -181,13 +240,17 @@ bool AppBannerManager::FetchIcon(JNIEnv* env, ...@@ -181,13 +240,17 @@ bool AppBannerManager::FetchIcon(JNIEnv* env,
jobject obj, jobject obj,
jstring jimage_url) { jstring jimage_url) {
std::string image_url = ConvertJavaStringToUTF8(env, jimage_url); std::string image_url = ConvertJavaStringToUTF8(env, jimage_url);
return FetchIcon(GURL(image_url));
}
bool AppBannerManager::FetchIcon(const GURL& image_url) {
if (!web_contents()) if (!web_contents())
return false; return false;
// Begin asynchronously fetching the app icon. // Begin asynchronously fetching the app icon.
Profile* profile = Profile* profile =
Profile::FromBrowserContext(web_contents()->GetBrowserContext()); Profile::FromBrowserContext(web_contents()->GetBrowserContext());
fetcher_.reset(new chrome::BitmapFetcher(GURL(image_url), this)); fetcher_.reset(new chrome::BitmapFetcher(image_url, this));
fetcher_.get()->Start( fetcher_.get()->Start(
profile->GetRequestContext(), profile->GetRequestContext(),
std::string(), std::string(),
...@@ -196,6 +259,15 @@ bool AppBannerManager::FetchIcon(JNIEnv* env, ...@@ -196,6 +259,15 @@ bool AppBannerManager::FetchIcon(JNIEnv* env,
return true; return true;
} }
int AppBannerManager::GetPreferredIconSize() {
JNIEnv* env = base::android::AttachCurrentThread();
ScopedJavaLocalRef<jobject> jobj = weak_java_banner_view_manager_.get(env);
if (jobj.is_null())
return 0;
return Java_AppBannerManager_getPreferredIconSize(env, jobj.obj());
}
void RecordDismissEvent(JNIEnv* env, jclass clazz, jint metric) { void RecordDismissEvent(JNIEnv* env, jclass clazz, jint metric) {
banners::TrackDismissEvent(metric); banners::TrackDismissEvent(metric);
} }
......
...@@ -8,8 +8,10 @@ ...@@ -8,8 +8,10 @@
#include "base/android/jni_android.h" #include "base/android/jni_android.h"
#include "base/android/jni_weak_ref.h" #include "base/android/jni_weak_ref.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "chrome/browser/android/banners/app_banner_infobar_delegate.h"
#include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h" #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
#include "content/public/common/manifest.h"
namespace content { namespace content {
struct FrameNavigateParams; struct FrameNavigateParams;
...@@ -58,7 +60,8 @@ struct Manifest; ...@@ -58,7 +60,8 @@ struct Manifest;
namespace banners { namespace banners {
class AppBannerManager : public chrome::BitmapFetcherDelegate, class AppBannerManager : public chrome::BitmapFetcherDelegate,
public content::WebContentsObserver { public content::WebContentsObserver,
public AppBannerInfoBarDelegate::AppDelegate {
public: public:
AppBannerManager(JNIEnv* env, jobject obj); AppBannerManager(JNIEnv* env, jobject obj);
virtual ~AppBannerManager(); virtual ~AppBannerManager();
...@@ -74,12 +77,16 @@ class AppBannerManager : public chrome::BitmapFetcherDelegate, ...@@ -74,12 +77,16 @@ class AppBannerManager : public chrome::BitmapFetcherDelegate,
jobject obj, jobject obj,
jobject jweb_contents); jobject jweb_contents);
// Fetches the icon at the give URL. // Fetches the icon at the given URL asynchronously.
// Returns |false| if this couldn't be kicked off. // Returns |false| if this couldn't be kicked off.
bool FetchIcon(JNIEnv* env, bool FetchIcon(JNIEnv* env,
jobject obj, jobject obj,
jstring jimage_url); jstring jimage_url);
// Fetches the icon at the given URL asynchronously.
// Returns |false| if this couldn't be kicked off.
bool FetchIcon(const GURL& image_url);
// WebContentsObserver overrides. // WebContentsObserver overrides.
virtual void DidNavigateMainFrame( virtual void DidNavigateMainFrame(
const content::LoadCommittedDetails& details, const content::LoadCommittedDetails& details,
...@@ -88,11 +95,18 @@ class AppBannerManager : public chrome::BitmapFetcherDelegate, ...@@ -88,11 +95,18 @@ class AppBannerManager : public chrome::BitmapFetcherDelegate,
const GURL& validated_url) override; const GURL& validated_url) override;
virtual bool OnMessageReceived(const IPC::Message& message) override; virtual bool OnMessageReceived(const IPC::Message& message) override;
// BitmapFetcherDelegate overrides. // BitmapFetcherDelegate overrides.
virtual void OnFetchComplete(const GURL url, const SkBitmap* bitmap) override; virtual void OnFetchComplete(const GURL url, const SkBitmap* bitmap) override;
// AppBannerInfoBarDelegate::AppDelegate overrides.
virtual void Block() const override;
virtual void Install() const override;
virtual gfx::Image GetIcon() const override;
private: private:
// Gets the preferred icon size for the banner icons.
int GetPreferredIconSize();
// Called when the manifest has been retrieved, or if there is no manifest to // Called when the manifest has been retrieved, or if there is no manifest to
// retrieve. // retrieve.
void OnDidGetManifest(const content::Manifest& manifest); void OnDidGetManifest(const content::Manifest& manifest);
...@@ -109,6 +123,8 @@ class AppBannerManager : public chrome::BitmapFetcherDelegate, ...@@ -109,6 +123,8 @@ class AppBannerManager : public chrome::BitmapFetcherDelegate,
// Fetches the icon for an app. // Fetches the icon for an app.
scoped_ptr<chrome::BitmapFetcher> fetcher_; scoped_ptr<chrome::BitmapFetcher> fetcher_;
GURL validated_url_; GURL validated_url_;
content::Manifest manifest_;
scoped_ptr<SkBitmap> app_icon_;
// AppBannerManager on the Java side. // AppBannerManager on the Java side.
JavaObjectWeakGlobalRef weak_java_banner_view_manager_; JavaObjectWeakGlobalRef weak_java_banner_view_manager_;
......
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
'browser/android/activity_type_ids.h', 'browser/android/activity_type_ids.h',
'browser/android/appmenu/app_menu_drag_helper.cc', 'browser/android/appmenu/app_menu_drag_helper.cc',
'browser/android/appmenu/app_menu_drag_helper.h', 'browser/android/appmenu/app_menu_drag_helper.h',
'browser/android/banners/app_banner_infobar_delegate.cc',
'browser/android/banners/app_banner_infobar_delegate.h',
'browser/android/banners/app_banner_manager.cc', 'browser/android/banners/app_banner_manager.cc',
'browser/android/banners/app_banner_manager.h', 'browser/android/banners/app_banner_manager.h',
'browser/android/banners/app_banner_metrics_id_list.h', 'browser/android/banners/app_banner_metrics_id_list.h',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment