Commit 641ed0eb authored by Michael van Ouwerkerk's avatar Michael van Ouwerkerk Committed by Commit Bot

Reland WebAPK Site Settings Shortcut using startActivityForResult.

Bug: 1138210
Change-Id: I95d57fb3fe0802298fad44d4415aaac7e87871bd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2510250Reviewed-by: default avatarPeter Conn <peconn@chromium.org>
Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Commit-Queue: Michael van Ouwerkerk <mvanouwerkerk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#824882}
parent cd7c8f92
...@@ -75,6 +75,7 @@ chrome_test_java_sources = [ ...@@ -75,6 +75,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java", "javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java",
"javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java", "javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java",
"javatests/src/org/chromium/chrome/browser/bookmarks/bottomsheet/BookmarkBottomSheetTest.java", "javatests/src/org/chromium/chrome/browser/bookmarks/bottomsheet/BookmarkBottomSheetTest.java",
"javatests/src/org/chromium/chrome/browser/browserservices/ManageTrustedWebActivityDataActivityTest.java",
"javatests/src/org/chromium/chrome/browser/browserservices/OriginVerifierTest.java", "javatests/src/org/chromium/chrome/browser/browserservices/OriginVerifierTest.java",
"javatests/src/org/chromium/chrome/browser/browserservices/QualityEnforcerTest.java", "javatests/src/org/chromium/chrome/browser/browserservices/QualityEnforcerTest.java",
"javatests/src/org/chromium/chrome/browser/browserservices/RunningInChromeTest.java", "javatests/src/org/chromium/chrome/browser/browserservices/RunningInChromeTest.java",
......
...@@ -1116,6 +1116,7 @@ ...@@ -1116,6 +1116,7 @@
<category android:name="androidx.browser.customtabs.category.NavBarColorCustomization"/> <category android:name="androidx.browser.customtabs.category.NavBarColorCustomization"/>
<category android:name="androidx.browser.trusted.category.ImmersiveMode"/> <category android:name="androidx.browser.trusted.category.ImmersiveMode"/>
<category android:name="androidx.browser.trusted.category.LaunchSiteSettings"/> <category android:name="androidx.browser.trusted.category.LaunchSiteSettings"/>
<category android:name="androidx.browser.trusted.category.LaunchWebApkSiteSettings"/>
<category android:name="androidx.browser.trusted.category.TrustedWebActivities"/> <category android:name="androidx.browser.trusted.category.TrustedWebActivities"/>
<category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/> <category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/>
<category android:name="androidx.browser.trusted.category.WebShareTargetV2"/> <category android:name="androidx.browser.trusted.category.WebShareTargetV2"/>
......
...@@ -1018,6 +1018,7 @@ ...@@ -1018,6 +1018,7 @@
<category android:name="androidx.browser.customtabs.category.NavBarColorCustomization"/> <category android:name="androidx.browser.customtabs.category.NavBarColorCustomization"/>
<category android:name="androidx.browser.trusted.category.ImmersiveMode"/> <category android:name="androidx.browser.trusted.category.ImmersiveMode"/>
<category android:name="androidx.browser.trusted.category.LaunchSiteSettings"/> <category android:name="androidx.browser.trusted.category.LaunchSiteSettings"/>
<category android:name="androidx.browser.trusted.category.LaunchWebApkSiteSettings"/>
<category android:name="androidx.browser.trusted.category.TrustedWebActivities"/> <category android:name="androidx.browser.trusted.category.TrustedWebActivities"/>
<category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/> <category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/>
<category android:name="androidx.browser.trusted.category.WebShareTargetV2"/> <category android:name="androidx.browser.trusted.category.WebShareTargetV2"/>
......
...@@ -1069,6 +1069,7 @@ by a child template that "extends" this file. ...@@ -1069,6 +1069,7 @@ by a child template that "extends" this file.
<category android:name="androidx.browser.customtabs.category.NavBarColorCustomization"/> <category android:name="androidx.browser.customtabs.category.NavBarColorCustomization"/>
<category android:name="androidx.browser.trusted.category.ImmersiveMode"/> <category android:name="androidx.browser.trusted.category.ImmersiveMode"/>
<category android:name="androidx.browser.trusted.category.LaunchSiteSettings" /> <category android:name="androidx.browser.trusted.category.LaunchSiteSettings" />
<category android:name="androidx.browser.trusted.category.LaunchWebApkSiteSettings"/>
<category android:name="androidx.browser.trusted.category.TrustedWebActivities"/> <category android:name="androidx.browser.trusted.category.TrustedWebActivities"/>
<category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/> <category android:name="androidx.browser.trusted.category.TrustedWebActivitySplashScreensV1"/>
<category android:name="androidx.browser.trusted.category.WebShareTargetV2"/> <category android:name="androidx.browser.trusted.category.WebShareTargetV2"/>
......
...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.browserservices; ...@@ -7,6 +7,7 @@ package org.chromium.chrome.browser.browserservices;
import android.os.Bundle; import android.os.Bundle;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.browser.customtabs.CustomTabsSessionToken; import androidx.browser.customtabs.CustomTabsSessionToken;
...@@ -14,6 +15,7 @@ import org.chromium.base.Log; ...@@ -14,6 +15,7 @@ import org.chromium.base.Log;
import org.chromium.chrome.browser.ChromeApplication; import org.chromium.chrome.browser.ChromeApplication;
import org.chromium.chrome.browser.customtabs.CustomTabsConnection; import org.chromium.chrome.browser.customtabs.CustomTabsConnection;
import org.chromium.chrome.browser.init.ChromeBrowserInitializer; import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
import org.chromium.webapk.lib.common.WebApkConstants;
/** /**
* Launched by Trusted Web Activity apps when the user clears data. * Launched by Trusted Web Activity apps when the user clears data.
...@@ -25,15 +27,20 @@ public class ManageTrustedWebActivityDataActivity extends AppCompatActivity { ...@@ -25,15 +27,20 @@ public class ManageTrustedWebActivityDataActivity extends AppCompatActivity {
private static final String TAG = "TwaDataActivity"; private static final String TAG = "TwaDataActivity";
private static String sMockCallingPackage;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
launchSettings();
String urlToLaunchSettingsFor = getIntent().getData().toString();
boolean isWebApk = getIntent().getBooleanExtra(WebApkConstants.EXTRA_IS_WEBAPK, false);
launchSettings(urlToLaunchSettingsFor, isWebApk);
finish(); finish();
} }
private void launchSettings() { private void launchSettings(@Nullable String urlToLaunchSettingsFor, boolean isWebApk) {
String packageName = getClientPackageName(); String packageName = getClientPackageName(isWebApk);
if (packageName == null) { if (packageName == null) {
logNoPackageName(); logNoPackageName();
finish(); finish();
...@@ -41,11 +48,26 @@ public class ManageTrustedWebActivityDataActivity extends AppCompatActivity { ...@@ -41,11 +48,26 @@ public class ManageTrustedWebActivityDataActivity extends AppCompatActivity {
} }
new TrustedWebActivityUmaRecorder(ChromeBrowserInitializer.getInstance()) new TrustedWebActivityUmaRecorder(ChromeBrowserInitializer.getInstance())
.recordOpenedSettingsViaManageSpace(); .recordOpenedSettingsViaManageSpace();
TrustedWebActivitySettingsLauncher.launchForPackageName(this, packageName);
if (isWebApk) {
TrustedWebActivitySettingsLauncher.launchForWebApkPackageName(
this, packageName, urlToLaunchSettingsFor);
} else {
TrustedWebActivitySettingsLauncher.launchForPackageName(this, packageName);
}
}
@VisibleForTesting
public static void setCallingPackageForTesting(String packageName) {
sMockCallingPackage = packageName;
} }
@Nullable @Nullable
private String getClientPackageName() { private String getClientPackageName(boolean isWebApk) {
if (isWebApk) {
return sMockCallingPackage != null ? sMockCallingPackage : getCallingPackage();
}
CustomTabsSessionToken session = CustomTabsSessionToken session =
CustomTabsSessionToken.getSessionTokenFromIntent(getIntent()); CustomTabsSessionToken.getSessionTokenFromIntent(getIntent());
if (session == null) { if (session == null) {
......
...@@ -13,10 +13,12 @@ import org.chromium.base.Log; ...@@ -13,10 +13,12 @@ import org.chromium.base.Log;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.settings.SettingsLauncher; import org.chromium.chrome.browser.settings.SettingsLauncher;
import org.chromium.chrome.browser.settings.SettingsLauncherImpl; import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
import org.chromium.chrome.browser.webapps.ChromeWebApkHost;
import org.chromium.components.browser_ui.site_settings.AllSiteSettings; import org.chromium.components.browser_ui.site_settings.AllSiteSettings;
import org.chromium.components.browser_ui.site_settings.SettingsNavigationSource; import org.chromium.components.browser_ui.site_settings.SettingsNavigationSource;
import org.chromium.components.browser_ui.site_settings.SingleWebsiteSettings; import org.chromium.components.browser_ui.site_settings.SingleWebsiteSettings;
import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory; import org.chromium.components.browser_ui.site_settings.SiteSettingsCategory;
import org.chromium.components.webapk.lib.client.WebApkValidator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
...@@ -33,13 +35,8 @@ public class TrustedWebActivitySettingsLauncher { ...@@ -33,13 +35,8 @@ public class TrustedWebActivitySettingsLauncher {
* able to work with each of them. * able to work with each of them.
*/ */
public static void launchForPackageName(Context context, String packageName) { public static void launchForPackageName(Context context, String packageName) {
int applicationUid; Integer applicationUid = getApplicationUid(context, packageName);
try { if (applicationUid == null) return;
applicationUid = context.getPackageManager().getApplicationInfo(packageName, 0).uid;
} catch (PackageManager.NameNotFoundException e) {
Log.d(TAG, "Package " + packageName + " not found");
return;
}
ClientAppDataRegister register = new ClientAppDataRegister(); ClientAppDataRegister register = new ClientAppDataRegister();
Collection<String> domains = register.getDomainsForRegisteredUid(applicationUid); Collection<String> domains = register.getDomainsForRegisteredUid(applicationUid);
...@@ -51,6 +48,33 @@ public class TrustedWebActivitySettingsLauncher { ...@@ -51,6 +48,33 @@ public class TrustedWebActivitySettingsLauncher {
launch(context, origins, domains); launch(context, origins, domains);
} }
/**
* Launches site-settings for a WebApk with a given package name and associated url.
*/
public static void launchForWebApkPackageName(
Context context, String packageName, String webApkUrl) {
if (!WebApkValidator.canWebApkHandleUrl(context, packageName, webApkUrl)) {
Log.d(TAG, "WebApk " + packageName + " can't handle url " + webApkUrl);
return;
}
if (getApplicationUid(context, packageName) == null) return;
// Handle the case when settings are selected but Chrome was not running.
ChromeWebApkHost.init();
openSingleWebsitePrefs(context, webApkUrl);
}
private static Integer getApplicationUid(Context context, String packageName) {
int applicationUid;
try {
applicationUid = context.getPackageManager().getApplicationInfo(packageName, 0).uid;
} catch (PackageManager.NameNotFoundException e) {
Log.d(TAG, "Package " + packageName + " not found");
return null;
}
return applicationUid;
}
/** /**
* Same as above, but with list of associated origins and domains already retrieved. * Same as above, but with list of associated origins and domains already retrieved.
*/ */
......
// Copyright 2020 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.browserservices;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.support.test.InstrumentationRegistry;
import androidx.test.filters.MediumTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.Matchers;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.components.webapk.lib.client.WebApkValidator;
import org.chromium.content_public.browser.test.util.Criteria;
import org.chromium.content_public.browser.test.util.CriteriaHelper;
import org.chromium.webapk.lib.common.WebApkConstants;
/**
* Instrumentation tests for launching site settings for WebApks.
* Site settings are added as a dynamic android shortcut.
* The shortcut launches a {@link ManageTrustedWebActivityDataActivity}
* intent that validates the WebApk and launches the chromium SettingsActivity.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class ManageTrustedWebActivityDataActivityTest {
private static final String SETTINGS_ACTIVITY_NAME =
"org.chromium.chrome.browser.settings.SettingsActivity";
private static final String WEBAPK_TEST_URL = "https://www.example.com";
private static final String TEST_PACKAGE_NAME =
InstrumentationRegistry.getTargetContext().getPackageName();
@Test
@MediumTest
public void launchesWebApkSiteSettings() throws Exception {
WebApkValidator.setDisableValidationForTesting(true);
ManageTrustedWebActivityDataActivity.setCallingPackageForTesting(TEST_PACKAGE_NAME);
TrustedWebActivityTestUtil.spoofVerification(TEST_PACKAGE_NAME, WEBAPK_TEST_URL);
launchSettings(TEST_PACKAGE_NAME, Uri.parse(WEBAPK_TEST_URL));
// Check settings activity is running.
CriteriaHelper.pollUiThread(() -> {
try {
Criteria.checkThat("Site settings activity was not launched",
siteSettingsActivityRunning(), Matchers.is(true));
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
});
}
private boolean siteSettingsActivityRunning() throws PackageManager.NameNotFoundException {
for (Activity a : ApplicationStatus.getRunningActivities()) {
String activityName =
a.getPackageManager().getActivityInfo(a.getComponentName(), 0).name;
if (activityName.equals(SETTINGS_ACTIVITY_NAME)) {
return true;
}
}
return false;
}
private static void launchSettings(String packageName, Uri uri) {
Intent intent = new Intent();
intent.setAction(
"android.support.customtabs.action.ACTION_MANAGE_TRUSTED_WEB_ACTIVITY_DATA");
intent.setPackage(packageName);
intent.setData(uri);
intent.putExtra(WebApkConstants.EXTRA_IS_WEBAPK, true);
// The following flag is required because the test starts the intent outside of an activity.
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
}
}
...@@ -33,6 +33,7 @@ public final class WebApkConstants { ...@@ -33,6 +33,7 @@ public final class WebApkConstants {
"org.chromium.chrome.browser.webapk.splash_provided_by_webapk"; "org.chromium.chrome.browser.webapk.splash_provided_by_webapk";
// Tells the host browser to relaunch the WebAPK. // Tells the host browser to relaunch the WebAPK.
public static final String EXTRA_RELAUNCH = "org.chromium.webapk.relaunch"; public static final String EXTRA_RELAUNCH = "org.chromium.webapk.relaunch";
public static final String EXTRA_IS_WEBAPK = "org.chromium.webapk.is_webapk";
// Must be kept in sync with chrome/browser/android/shortcut_info.h. // Must be kept in sync with chrome/browser/android/shortcut_info.h.
public static final int SHORTCUT_SOURCE_UNKNOWN = 0; public static final int SHORTCUT_SOURCE_UNKNOWN = 0;
......
...@@ -32,6 +32,10 @@ ...@@ -32,6 +32,10 @@
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" /> <data android:scheme="https" />
</intent> </intent>
<intent>
<action android:name="android.support.customtabs.action.ACTION_MANAGE_TRUSTED_WEB_ACTIVITY_DATA" />
<data android:scheme="https" />
</intent>
</queries> </queries>
<application <application
...@@ -59,6 +63,10 @@ ...@@ -59,6 +63,10 @@
{{{raw_intent_filters}}} {{{raw_intent_filters}}}
</activity> </activity>
<activity android:name="org.chromium.webapk.shell_apk.ManageDataLauncherActivity"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
</activity>
<activity android:name="org.chromium.webapk.shell_apk.h2o.H2OOpaqueMainActivity" <activity android:name="org.chromium.webapk.shell_apk.h2o.H2OOpaqueMainActivity"
android:theme="@style/SplashTheme" android:theme="@style/SplashTheme"
android:relinquishTaskIdentity="true" android:relinquishTaskIdentity="true"
......
...@@ -61,6 +61,7 @@ template("webapk_java") { ...@@ -61,6 +61,7 @@ template("webapk_java") {
"src/org/chromium/webapk/shell_apk/IdentityService.java", "src/org/chromium/webapk/shell_apk/IdentityService.java",
"src/org/chromium/webapk/shell_apk/InstallHostBrowserDialog.java", "src/org/chromium/webapk/shell_apk/InstallHostBrowserDialog.java",
"src/org/chromium/webapk/shell_apk/LaunchHostBrowserSelector.java", "src/org/chromium/webapk/shell_apk/LaunchHostBrowserSelector.java",
"src/org/chromium/webapk/shell_apk/ManageDataLauncherActivity.java",
"src/org/chromium/webapk/shell_apk/TransparentLauncherActivity.java", "src/org/chromium/webapk/shell_apk/TransparentLauncherActivity.java",
"src/org/chromium/webapk/shell_apk/WebApkSharedPreferences.java", "src/org/chromium/webapk/shell_apk/WebApkSharedPreferences.java",
"src/org/chromium/webapk/shell_apk/WebApkUtils.java", "src/org/chromium/webapk/shell_apk/WebApkUtils.java",
...@@ -150,6 +151,7 @@ template("webapk_tmpl") { ...@@ -150,6 +151,7 @@ template("webapk_tmpl") {
android_resources(_resources_target_name) { android_resources(_resources_target_name) {
sources = [ sources = [
"res/drawable-hdpi/ic_site_settings.png",
"res/drawable-hdpi/last_resort_runtime_host_logo.png", "res/drawable-hdpi/last_resort_runtime_host_logo.png",
"res/drawable-hdpi/notification_badge.png", "res/drawable-hdpi/notification_badge.png",
"res/drawable-hdpi/shortcut_1_icon.png", "res/drawable-hdpi/shortcut_1_icon.png",
...@@ -157,24 +159,28 @@ template("webapk_tmpl") { ...@@ -157,24 +159,28 @@ template("webapk_tmpl") {
"res/drawable-hdpi/shortcut_3_icon.png", "res/drawable-hdpi/shortcut_3_icon.png",
"res/drawable-hdpi/shortcut_4_icon.png", "res/drawable-hdpi/shortcut_4_icon.png",
"res/drawable-hdpi/splash_icon.xml", "res/drawable-hdpi/splash_icon.xml",
"res/drawable-mdpi/ic_site_settings.png",
"res/drawable-mdpi/notification_badge.png", "res/drawable-mdpi/notification_badge.png",
"res/drawable-mdpi/shortcut_1_icon.png", "res/drawable-mdpi/shortcut_1_icon.png",
"res/drawable-mdpi/shortcut_2_icon.png", "res/drawable-mdpi/shortcut_2_icon.png",
"res/drawable-mdpi/shortcut_3_icon.png", "res/drawable-mdpi/shortcut_3_icon.png",
"res/drawable-mdpi/shortcut_4_icon.png", "res/drawable-mdpi/shortcut_4_icon.png",
"res/drawable-mdpi/splash_icon.xml", "res/drawable-mdpi/splash_icon.xml",
"res/drawable-xhdpi/ic_site_settings.png",
"res/drawable-xhdpi/notification_badge.png", "res/drawable-xhdpi/notification_badge.png",
"res/drawable-xhdpi/shortcut_1_icon.png", "res/drawable-xhdpi/shortcut_1_icon.png",
"res/drawable-xhdpi/shortcut_2_icon.png", "res/drawable-xhdpi/shortcut_2_icon.png",
"res/drawable-xhdpi/shortcut_3_icon.png", "res/drawable-xhdpi/shortcut_3_icon.png",
"res/drawable-xhdpi/shortcut_4_icon.png", "res/drawable-xhdpi/shortcut_4_icon.png",
"res/drawable-xhdpi/splash_icon.xml", "res/drawable-xhdpi/splash_icon.xml",
"res/drawable-xxhdpi/ic_site_settings.png",
"res/drawable-xxhdpi/notification_badge.png", "res/drawable-xxhdpi/notification_badge.png",
"res/drawable-xxhdpi/shortcut_1_icon.png", "res/drawable-xxhdpi/shortcut_1_icon.png",
"res/drawable-xxhdpi/shortcut_2_icon.png", "res/drawable-xxhdpi/shortcut_2_icon.png",
"res/drawable-xxhdpi/shortcut_3_icon.png", "res/drawable-xxhdpi/shortcut_3_icon.png",
"res/drawable-xxhdpi/shortcut_4_icon.png", "res/drawable-xxhdpi/shortcut_4_icon.png",
"res/drawable-xxhdpi/splash_icon.xml", "res/drawable-xxhdpi/splash_icon.xml",
"res/drawable-xxxhdpi/ic_site_settings.png",
"res/drawable-xxxhdpi/notification_badge.png", "res/drawable-xxxhdpi/notification_badge.png",
"res/drawable-xxxhdpi/shortcut_1_icon.png", "res/drawable-xxxhdpi/shortcut_1_icon.png",
"res/drawable-xxxhdpi/shortcut_2_icon.png", "res/drawable-xxxhdpi/shortcut_2_icon.png",
......
...@@ -12,4 +12,4 @@ ...@@ -12,4 +12,4 @@
# //chrome/android/webapk/shell_apk:webapk is changed. This includes # //chrome/android/webapk/shell_apk:webapk is changed. This includes
# Java files, Android resource files and AndroidManifest.xml. Does not affect # Java files, Android resource files and AndroidManifest.xml. Does not affect
# Chrome.apk # Chrome.apk
current_shell_apk_version = 132 current_shell_apk_version = 133
...@@ -34,8 +34,6 @@ public class HostBrowserLauncher { ...@@ -34,8 +34,6 @@ public class HostBrowserLauncher {
* Otherwise, launches the host browser in tabbed mode. * Otherwise, launches the host browser in tabbed mode.
*/ */
public static void launch(Activity activity, HostBrowserLauncherParams params) { public static void launch(Activity activity, HostBrowserLauncherParams params) {
Log.v(TAG, "WebAPK Launch URL: " + params.getStartUrl());
if (HostBrowserUtils.shouldLaunchInTab(params)) { if (HostBrowserUtils.shouldLaunchInTab(params)) {
launchInTab(activity.getApplicationContext(), params); launchInTab(activity.getApplicationContext(), params);
return; return;
...@@ -48,6 +46,8 @@ public class HostBrowserLauncher { ...@@ -48,6 +46,8 @@ public class HostBrowserLauncher {
/** Launches host browser in WebAPK mode. */ /** Launches host browser in WebAPK mode. */
public static void launchBrowserInWebApkMode(Activity activity, public static void launchBrowserInWebApkMode(Activity activity,
HostBrowserLauncherParams params, Bundle extraExtras, int flags, boolean expectResult) { HostBrowserLauncherParams params, Bundle extraExtras, int flags, boolean expectResult) {
ManageDataLauncherActivity.updateSiteSettingsShortcut(
activity.getApplicationContext(), params);
Intent intent = new Intent(); Intent intent = new Intent();
intent.setAction(ACTION_START_WEBAPK); intent.setAction(ACTION_START_WEBAPK);
intent.setPackage(params.getHostBrowserPackageName()); intent.setPackage(params.getHostBrowserPackageName());
...@@ -102,6 +102,7 @@ public class HostBrowserLauncher { ...@@ -102,6 +102,7 @@ public class HostBrowserLauncher {
/** Launches a WebAPK in its runtime host browser as a tab. */ /** Launches a WebAPK in its runtime host browser as a tab. */
private static void launchInTab(Context context, HostBrowserLauncherParams params) { private static void launchInTab(Context context, HostBrowserLauncherParams params) {
ManageDataLauncherActivity.updateSiteSettingsShortcut(context, params);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(params.getStartUrl())); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(params.getStartUrl()));
intent.setPackage(params.getHostBrowserPackageName()); intent.setPackage(params.getHostBrowserPackageName());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
......
// Copyright 2020 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.webapk.shell_apk;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.Toast;
import org.chromium.webapk.lib.common.WebApkConstants;
import java.util.Collections;
import java.util.List;
/**
* Handles site settings shortcuts for WebApks. The shortcut opens the web
* browser's site settings for the start url associated with the WebApk.
*/
public class ManageDataLauncherActivity extends Activity {
public static final String ACTION_SITE_SETTINGS =
"android.support.customtabs.action.ACTION_MANAGE_TRUSTED_WEB_ACTIVITY_DATA";
public static final String SITE_SETTINGS_SHORTCUT_ID =
"android.support.customtabs.action.SITE_SETTINGS_SHORTCUT";
private static final String EXTRA_SITE_SETTINGS_URL = "SITE_SETTINGS_URL";
private static final String EXTRA_PROVIDER_PACKAGE = "PROVIDER_PACKAGE";
private static final String CATEGORY_LAUNCH_WEBAPK_SITE_SETTINGS =
"androidx.browser.trusted.category.LaunchWebApkSiteSettings";
private static final String ACTION_CUSTOM_TABS_CONNECTION =
"android.support.customtabs.action.CustomTabsService";
private String mProviderPackage;
/**
* The url of the page for which the settings will be shown. Must be provided as an intent
* extra to {@link ManageDataLauncherActivity}.
*/
private Uri mUrl;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mProviderPackage = getIntent().getStringExtra(EXTRA_PROVIDER_PACKAGE);
mUrl = Uri.parse(getIntent().getStringExtra(EXTRA_SITE_SETTINGS_URL));
if (!supportsLaunchSettings(this, mProviderPackage)) {
handleNoSupportForLaunchSettings();
return;
}
setContentView(createLoadingView());
launchSettings();
}
/**
* Returns a view with a loading spinner.
*/
private View createLoadingView() {
ProgressBar progressBar = new ProgressBar(this);
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
params.gravity = Gravity.CENTER;
progressBar.setLayoutParams(params);
FrameLayout layout = new FrameLayout(this);
layout.addView(progressBar);
return layout;
}
/**
* Called if a provider doesn't support the launch settings feature. Shows a toast telling the
* user how to fix it, then finishes the activity.
*/
private void handleNoSupportForLaunchSettings() {
String appName;
try {
ApplicationInfo info = getPackageManager().getApplicationInfo(mProviderPackage, 0);
appName = getPackageManager().getApplicationLabel(info).toString();
} catch (PackageManager.NameNotFoundException e) {
appName = mProviderPackage;
}
Toast.makeText(this, getString(R.string.no_support_for_launch_settings, appName),
Toast.LENGTH_LONG)
.show();
finish();
}
@Override
protected void onStop() {
super.onStop();
finish();
}
private void launchSettings() {
Intent intent = new Intent();
intent.setAction(ACTION_SITE_SETTINGS);
intent.setPackage(mProviderPackage);
intent.setData(mUrl);
intent.putExtra(WebApkConstants.EXTRA_IS_WEBAPK, true);
try {
startActivityForResult(intent, 0 /* requestCode */);
finish();
} catch (ActivityNotFoundException e) {
handleNoSupportForLaunchSettings();
}
}
private static boolean supportsLaunchSettings(Context context, String providerPackage) {
Intent intent = new Intent(ACTION_CUSTOM_TABS_CONNECTION);
intent.addCategory(CATEGORY_LAUNCH_WEBAPK_SITE_SETTINGS);
intent.setPackage(providerPackage);
List<ResolveInfo> services = context.getPackageManager().queryIntentServices(
intent, PackageManager.GET_RESOLVED_FILTER);
return services.size() > 0;
}
/**
* Returns the {@link ShortcutInfo} for a dynamic shortcut into site settings,
* provided that {@link ManageDataLauncherActivity} is present in the manifest
* and an Intent for managing site settings is available.
*
* Otherwise returns null if {@link ManageDataLauncherActivity} is not launchable
* or if shortcuts are not supported by the Android SDK version.
*
* The shortcut returned does not specify an activity. Thus when the shortcut is added,
* the app's main activity will be used by default. This activity needs to define the
* MAIN action and LAUNCHER category in order to attach the shortcut.
*/
@TargetApi(Build.VERSION_CODES.N_MR1)
private static ShortcutInfo createSiteSettingsShortcutInfo(
Context context, String url, String providerPackage) {
Intent siteSettingsIntent = new Intent(context, ManageDataLauncherActivity.class);
// Intent needs to have an action set, we can set an arbitrary action.
siteSettingsIntent.setAction(ACTION_SITE_SETTINGS);
siteSettingsIntent.putExtra(EXTRA_SITE_SETTINGS_URL, url);
siteSettingsIntent.putExtra(EXTRA_PROVIDER_PACKAGE, providerPackage);
return new ShortcutInfo.Builder(context, SITE_SETTINGS_SHORTCUT_ID)
.setShortLabel(context.getString(R.string.site_settings_short_label))
.setLongLabel(context.getString(R.string.site_settings_long_label))
.setIcon(Icon.createWithResource(context, R.drawable.ic_site_settings))
.setIntent(siteSettingsIntent)
.build();
}
/**
* Adds dynamic shortcut to site settings if the provider and android version support it.
*
* Removes previously added site settings shortcut if it is no longer supported, e.g. the user
* changed their default browser.
*/
public static void updateSiteSettingsShortcut(
Context context, HostBrowserLauncherParams params) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N_MR1) return;
ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class);
// Remove potentially existing shortcut if package does not support shortcuts.
if (!supportsLaunchSettings(context, params.getHostBrowserPackageName())) {
shortcutManager.removeDynamicShortcuts(Collections.singletonList(
ManageDataLauncherActivity.SITE_SETTINGS_SHORTCUT_ID));
return;
}
ShortcutInfo shortcut = createSiteSettingsShortcutInfo(
context, params.getStartUrl(), params.getHostBrowserPackageName());
shortcutManager.addDynamicShortcuts(Collections.singletonList(shortcut));
}
}
...@@ -167,6 +167,15 @@ ...@@ -167,6 +167,15 @@
</translations> </translations>
<release allow_pseudo="false" seq="1"> <release allow_pseudo="false" seq="1">
<messages fallback_to_english="true"> <messages fallback_to_english="true">
<message name="IDS_SITE_SETTINGS_LONG_LABEL" desc="Site settings Android app shortcut title to display on devices with larger screens. (ideally less than 25 characters)">
Site settings
</message>
<message name="IDS_SITE_SETTINGS_SHORT_LABEL" desc="Site settings Android app shortcut title. (ideally less than 10 characters)">
Site settings
</message>
<message name="IDS_NO_SUPPORT_FOR_LAUNCH_SETTINGS" desc="Text to show in a toast when a user clicks on a site settings shortcut but that feature is not supported by the browser.">
To open site settings, update or reinstall <ph name="BROWSER_NAME">%1$s<ex>Chrome</ex></ph>
</message>
<!-- Select host browser dialog --> <!-- Select host browser dialog -->
<message name="IDS_CHOOSE_HOST_BROWSER_DIALOG_TITLE" desc="Title for the host browser picker dialog, which is used to ask users to pick a browser to launch the installed WebAPK."> <message name="IDS_CHOOSE_HOST_BROWSER_DIALOG_TITLE" desc="Title for the host browser picker dialog, which is used to ask users to pick a browser to launch the installed WebAPK.">
<ph name="APP_NAME">%1$s<ex>Progressive Web Apps</ex></ph> requires a web browser <ph name="APP_NAME">%1$s<ex>Progressive Web Apps</ex></ph> requires a web browser
......
99afdcfb54eadd12dad55079e782f00e904764f0
\ No newline at end of file
f42d794cf577db2d062ce76e412b52351cfec17f
\ No newline at end of file
f42d794cf577db2d062ce76e412b52351cfec17f
\ No newline at end of file
...@@ -177,10 +177,16 @@ public class WebApkValidator { ...@@ -177,10 +177,16 @@ public class WebApkValidator {
*/ */
@SuppressLint("PackageManagerGetSignatures") @SuppressLint("PackageManagerGetSignatures")
public static boolean isValidWebApk(Context context, String webappPackageName) { public static boolean isValidWebApk(Context context, String webappPackageName) {
if (sOverrideValidationForTesting) {
if (DEBUG) {
Log.d(TAG, "WebApk validation is disabled for testing.");
}
return true;
}
if (sExpectedSignature == null || sCommentSignedPublicKeyBytes == null) { if (sExpectedSignature == null || sCommentSignedPublicKeyBytes == null) {
Log.wtf(TAG, Log.wtf(TAG,
"WebApk validation failure - expected signature not set." "WebApk validation failure - expected signature not set - "
+ "missing call to WebApkValidator.initWithBrowserHostSignature"); + "missing call to WebApkValidator.init");
return false; return false;
} }
PackageInfo packageInfo; PackageInfo packageInfo;
...@@ -197,12 +203,6 @@ public class WebApkValidator { ...@@ -197,12 +203,6 @@ public class WebApkValidator {
if (isNotWebApkQuick(packageInfo)) { if (isNotWebApkQuick(packageInfo)) {
return false; return false;
} }
if (sOverrideValidationForTesting) {
if (DEBUG) {
Log.d(TAG, "Ok! Looks like a WebApk (has start url) and validation is disabled.");
}
return true;
}
if (verifyV1WebApk(packageInfo, webappPackageName)) { if (verifyV1WebApk(packageInfo, webappPackageName)) {
return true; return true;
} }
......
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