Commit e01199c9 authored by Michael Thiessen's avatar Michael Thiessen Committed by Commit Bot

Add new shortcut type for Touchless mode - launching shortcuts as WebApps

We want shortcuts to feel more app-like as there are no tabs in
touchless mode and shortcuts clobbering your tab is confusing amongst
other things.

See bug for additional details.

Bug: 977198
Change-Id: I47c58ce218ffe6d0a146228fcd28c6c2e9b3abf0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1669235
Commit-Queue: Michael Thiessen <mthiesse@chromium.org>
Reviewed-by: default avatarRobert Sesek <rsesek@chromium.org>
Reviewed-by: default avatarPeter Kotwicz <pkotwicz@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#672094}
parent 2b17163b
......@@ -723,6 +723,16 @@ by a child template that "extends" this file.
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- Non-exported alias that only Chrome can launch to verify shortcut intent comes from
Chrome (ShortcutManager on O+ launches under the shortcut creator's uid). -->
<activity-alias android:name="org.chromium.chrome.browser.webapps.SecureWebAppLauncher"
android:targetActivity="org.chromium.chrome.browser.webapps.WebappLauncherActivity"
android:exported="false">
<intent-filter>
<action android:name="org.chromium.chrome.browser.webapps.WebappManager.ACTION_START_SECURE_WEBAPP" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity-alias>
<activity-alias android:name="com.google.android.apps.chrome.webapps.WebappManager"
android:targetActivity="org.chromium.chrome.browser.webapps.WebappLauncherActivity">
</activity-alias>
......
......@@ -955,6 +955,16 @@
<data android:scheme="file"/>
</intent-filter>
</activity>
<activity-alias
android:exported="false"
android:name="org.chromium.chrome.browser.webapps.SecureWebAppLauncher"
android:targetActivity="org.chromium.chrome.browser.webapps.WebappLauncherActivity">
<intent-filter>
<action
android:name="org.chromium.chrome.browser.webapps.WebappManager.ACTION_START_SECURE_WEBAPP"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity-alias>
<activity-alias
android:exported="true"
android:name="com.google.android.apps.chrome.IntentDispatcher"
......
......@@ -25,6 +25,7 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Base64;
......@@ -39,6 +40,8 @@ import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.task.AsyncTask;
import org.chromium.blink_public.platform.WebDisplayMode;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabThemeColorHelper;
import org.chromium.chrome.browser.util.FeatureUtilities;
import org.chromium.chrome.browser.webapps.WebApkInfo;
import org.chromium.chrome.browser.webapps.WebappActivity;
......@@ -48,6 +51,7 @@ import org.chromium.chrome.browser.webapps.WebappLauncherActivity;
import org.chromium.chrome.browser.webapps.WebappRegistry;
import org.chromium.chrome.browser.widget.RoundedIconGenerator;
import org.chromium.content_public.common.ScreenOrientationConstants;
import org.chromium.content_public.common.ScreenOrientationValues;
import org.chromium.ui.widget.Toast;
import org.chromium.webapk.lib.client.WebApkValidator;
......@@ -189,20 +193,30 @@ public class ShortcutHelper {
final String userTitle, final String name, final String shortName, final String iconUrl,
final Bitmap icon, boolean isIconAdaptive, @WebDisplayMode final int displayMode,
final int orientation, final int source, final long themeColor,
final long backgroundColor, final long callbackPointer) {
final long backgroundColor, final long callbackPointer,
final boolean isShortcutAsWebapp) {
new AsyncTask<Intent>() {
@Override
protected Intent doInBackground() {
// Encoding {@link icon} as a string and computing the mac are expensive.
// Shortcuts as Webapps on O+ launch into a non-exported component for verification.
boolean usesMacForVerification =
!isShortcutAsWebapp || Build.VERSION.SDK_INT < Build.VERSION_CODES.O;
// Encode the icon as a base64 string (Launcher drops Bitmaps in the Intent).
String encodedIcon = encodeBitmapAsString(icon);
Intent shortcutIntent = createWebappShortcutIntent(id,
sDelegate.getFullscreenAction(), url, scopeUrl, name, shortName,
encodedIcon, WEBAPP_SHORTCUT_VERSION, displayMode, orientation, themeColor,
backgroundColor, iconUrl.isEmpty(), isIconAdaptive);
shortcutIntent.putExtra(EXTRA_MAC, getEncodedMac(url));
String action = usesMacForVerification
? sDelegate.getFullscreenAction()
: WebappLauncherActivity.ACTION_START_SECURE_WEBAPP;
Intent shortcutIntent = createWebappShortcutIntent(id, action, url, scopeUrl, name,
shortName, encodedIcon, WEBAPP_SHORTCUT_VERSION, displayMode, orientation,
themeColor, backgroundColor, iconUrl.isEmpty(), isIconAdaptive);
if (usesMacForVerification) {
shortcutIntent.putExtra(EXTRA_MAC, getEncodedMac(url));
}
shortcutIntent.putExtra(EXTRA_SOURCE, source);
return shortcutIntent;
}
......@@ -213,11 +227,10 @@ public class ShortcutHelper {
// Store the webapp data so that it is accessible without the intent. Once this
// process is complete, call back to native code to start the splash image
// download.
WebappRegistry.getInstance().register(
id, storage -> {
storage.updateFromShortcutIntent(resultIntent);
nativeOnWebappDataStored(callbackPointer);
});
WebappRegistry.getInstance().register(id, storage -> {
storage.updateFromShortcutIntent(resultIntent);
if (callbackPointer != 0) nativeOnWebappDataStored(callbackPointer);
});
if (shouldShowToastWhenAddingShortcut()) {
showAddedToHomescreenToast(userTitle);
}
......@@ -231,13 +244,23 @@ public class ShortcutHelper {
*/
@SuppressWarnings("unused")
@CalledByNative
public static void addShortcut(String id, String url, String userTitle, Bitmap icon,
boolean isIconAdaptive, int source) {
Context context = ContextUtils.getApplicationContext();
final Intent shortcutIntent = createShortcutIntent(url);
public static void addShortcut(@Nullable Tab tab, String id, String url, String userTitle,
Bitmap icon, boolean isIconAdaptive, int source, String iconUrl) {
if (FeatureUtilities.isNoTouchModeEnabled()) {
// There are no tabs in NoTouchMode, so we want to give shortcuts a more app-like
// experience.
long themeColor = (tab == null) ? MANIFEST_COLOR_INVALID_OR_MISSING
: TabThemeColorHelper.getColor(tab);
addWebapp(id, url, getScopeFromUrl(url), userTitle, userTitle, userTitle, iconUrl, icon,
isIconAdaptive, WebDisplayMode.STANDALONE, ScreenOrientationValues.DEFAULT,
source, themeColor, MANIFEST_COLOR_INVALID_OR_MISSING, 0 /* callbackPointer */,
true /* isShortcutAsWebapp */);
return;
}
Intent shortcutIntent = createShortcutIntent(url);
shortcutIntent.putExtra(EXTRA_ID, id);
shortcutIntent.putExtra(EXTRA_SOURCE, source);
shortcutIntent.setPackage(context.getPackageName());
shortcutIntent.setPackage(ContextUtils.getApplicationContext().getPackageName());
sDelegate.addShortcutToHomescreen(userTitle, icon, isIconAdaptive, shortcutIntent);
if (shouldShowToastWhenAddingShortcut()) {
showAddedToHomescreenToast(userTitle);
......
......@@ -5,6 +5,7 @@
package org.chromium.chrome.browser.webapps;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
......@@ -48,6 +49,11 @@ public class WebappLauncherActivity extends Activity {
public static final String ACTION_START_WEBAPP =
"com.google.android.apps.chrome.webapps.WebappManager.ACTION_START_WEBAPP";
public static final String SECURE_WEBAPP_LAUNCHER =
"org.chromium.chrome.browser.webapps.SecureWebAppLauncher";
public static final String ACTION_START_SECURE_WEBAPP =
"org.chromium.chrome.browser.webapps.WebappManager.ACTION_START_SECURE_WEBAPP";
/**
* Delay in ms for relaunching WebAPK as a result of getting intent with extra
* {@link WebApkConstants.EXTRA_RELAUNCH}. The delay was chosen arbirtarily and seems to
......@@ -157,6 +163,12 @@ public class WebappLauncherActivity extends Activity {
// does not specify required values such as the uri.
if (webappInfo == null) return false;
// The component is not exported and can only be launched by Chrome.
if (intent.getComponent().equals(new ComponentName(
ContextUtils.getApplicationContext(), SECURE_WEBAPP_LAUNCHER))) {
return true;
}
String webappUrl = webappInfo.uri().toString();
String webappMac = IntentUtils.safeGetStringExtra(intent, ShortcutHelper.EXTRA_MAC);
......
......@@ -4,9 +4,9 @@
package org.chromium.chrome.browser.touchless;
import android.app.Activity;
import android.graphics.Bitmap;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ShortcutHelper;
import org.chromium.chrome.browser.webapps.AddToHomescreenDialog;
import org.chromium.chrome.browser.webapps.TouchlessAddToHomescreenDialog;
......@@ -16,14 +16,14 @@ import org.chromium.ui.modaldialog.ModalDialogManager;
* Add to homescreen manager specifically for touchless devices.
*/
class TouchlessAddToHomescreenManager implements AddToHomescreenDialog.Delegate {
private final Activity mActivity;
private final ChromeActivity mActivity;
private final ModalDialogManager mDialogManager;
private final String mUrl;
private final String mTitle;
private final Bitmap mIconBitmap;
public TouchlessAddToHomescreenManager(Activity activity, ModalDialogManager dialogManager,
String url, String title, Bitmap iconBitmap) {
public TouchlessAddToHomescreenManager(ChromeActivity activity,
ModalDialogManager dialogManager, String url, String title, Bitmap iconBitmap) {
mActivity = activity;
mDialogManager = dialogManager;
mUrl = url;
......@@ -42,7 +42,8 @@ class TouchlessAddToHomescreenManager implements AddToHomescreenDialog.Delegate
@Override
public void addToHomescreen(String title) {
ShortcutHelper.addShortcut(mUrl, mUrl, title, mIconBitmap, false, 0);
ShortcutHelper.addShortcut(
mActivity.getActivityTab(), mUrl, mUrl, title, mIconBitmap, false, 0, "");
}
@Override
......
......@@ -4,13 +4,13 @@
package org.chromium.chrome.browser.touchless;
import android.app.Activity;
import android.graphics.Bitmap;
import android.support.annotation.DrawableRes;
import android.support.annotation.StringRes;
import android.view.View;
import android.view.View.OnClickListener;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.native_page.ContextMenuManager;
import org.chromium.chrome.browser.native_page.NativePageNavigationDelegate;
import org.chromium.chrome.browser.touchless.dialog.TouchlessDialogProperties;
......@@ -59,12 +59,12 @@ public class TouchlessContextMenuManager extends ContextMenuManager {
}
}
private final Activity mActivity;
private final ChromeActivity mActivity;
private final ModalDialogManager mDialogManager;
private PropertyModel mTouchlessMenuModel;
private ModalDialogManager mModalDialogManager;
public TouchlessContextMenuManager(Activity activity, ModalDialogManager dialogManager,
public TouchlessContextMenuManager(ChromeActivity activity, ModalDialogManager dialogManager,
NativePageNavigationDelegate navigationDelegate,
TouchEnabledDelegate touchEnabledDelegate, Runnable closeContextMenuCallback,
String userActionPrefix) {
......
......@@ -20,6 +20,7 @@
#include "base/time/time.h"
#include "chrome/android/chrome_jni_headers/ShortcutHelper_jni.h"
#include "chrome/browser/android/color_helpers.h"
#include "chrome/browser/android/tab_android.h"
#include "chrome/browser/android/webapk/chrome_webapk_host.h"
#include "chrome/browser/android/webapk/webapk_install_service.h"
#include "chrome/browser/android/webapk/webapk_metrics.h"
......@@ -114,11 +115,13 @@ void AddWebappWithSkBitmap(const ShortcutInfo& info,
java_short_name, java_best_primary_icon_url, java_bitmap,
is_icon_maskable, info.display, info.orientation, info.source,
OptionalSkColorToJavaColor(info.theme_color),
OptionalSkColorToJavaColor(info.background_color), callback_pointer);
OptionalSkColorToJavaColor(info.background_color), callback_pointer,
false /* isShortcutAsWebapp */);
}
// Adds a shortcut which opens in a browser tab to the launcher.
void AddShortcutWithSkBitmap(const ShortcutInfo& info,
void AddShortcutWithSkBitmap(content::WebContents* web_contents,
const ShortcutInfo& info,
const std::string& id,
const SkBitmap& icon_bitmap,
bool is_icon_maskable) {
......@@ -129,12 +132,17 @@ void AddShortcutWithSkBitmap(const ShortcutInfo& info,
base::android::ConvertUTF8ToJavaString(env, info.url.spec());
ScopedJavaLocalRef<jstring> java_user_title =
base::android::ConvertUTF16ToJavaString(env, info.user_title);
ScopedJavaLocalRef<jstring> java_best_primary_icon_url =
base::android::ConvertUTF8ToJavaString(env,
info.best_primary_icon_url.spec());
ScopedJavaLocalRef<jobject> java_bitmap;
if (!icon_bitmap.drawsNothing())
java_bitmap = gfx::ConvertToJavaBitmap(&icon_bitmap);
Java_ShortcutHelper_addShortcut(env, java_id, java_url, java_user_title,
java_bitmap, is_icon_maskable, info.source);
TabAndroid* tab = TabAndroid::FromWebContents(web_contents);
Java_ShortcutHelper_addShortcut(env, tab ? tab->GetJavaObject() : nullptr,
java_id, java_url, java_user_title,
java_bitmap, is_icon_maskable, info.source,
java_best_primary_icon_url);
}
} // anonymous namespace
......@@ -183,7 +191,8 @@ void ShortcutHelper::AddToLauncherWithSkBitmap(
info.minimum_splash_image_size_in_px, webapp_id));
return;
}
AddShortcutWithSkBitmap(info, webapp_id, icon_bitmap, is_icon_maskable);
AddShortcutWithSkBitmap(web_contents, info, webapp_id, icon_bitmap,
is_icon_maskable);
}
void ShortcutHelper::ShowWebApkInstallInProgressToast() {
......
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