Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.webapk.shell_apk; | 5 package org.chromium.webapk.shell_apk; |
| 6 | 6 |
| 7 import android.app.Activity; | |
| 8 import android.content.ActivityNotFoundException; | 7 import android.content.ActivityNotFoundException; |
| 9 import android.content.Intent; | 8 import android.content.Intent; |
| 10 import android.content.pm.ApplicationInfo; | 9 import android.content.pm.ApplicationInfo; |
| 11 import android.content.pm.PackageManager; | 10 import android.content.pm.PackageManager; |
| 12 import android.content.pm.PackageManager.NameNotFoundException; | 11 import android.content.pm.PackageManager.NameNotFoundException; |
| 13 import android.net.Uri; | 12 import android.net.Uri; |
| 14 import android.os.Bundle; | 13 import android.os.Bundle; |
| 14 import android.support.v4.app.DialogFragment; | |
| 15 import android.support.v4.app.FragmentActivity; | |
| 16 import android.text.TextUtils; | |
| 15 import android.util.Log; | 17 import android.util.Log; |
| 16 | 18 |
| 17 import org.chromium.webapk.lib.common.WebApkConstants; | 19 import org.chromium.webapk.lib.common.WebApkConstants; |
| 18 import org.chromium.webapk.lib.common.WebApkMetaDataKeys; | 20 import org.chromium.webapk.lib.common.WebApkMetaDataKeys; |
| 19 | 21 |
| 20 import java.net.URISyntaxException; | 22 import java.net.MalformedURLException; |
| 23 import java.net.URL; | |
| 24 import java.util.Set; | |
| 21 | 25 |
| 22 /** | 26 /** |
| 23 * WebAPK's main Activity. | 27 * WebAPK's main Activity. |
| 24 */ | 28 */ |
| 25 public class MainActivity extends Activity { | 29 public class MainActivity |
| 30 extends FragmentActivity implements ChooseHostBrowserDialogFragment.Dial ogListener { | |
| 26 private static final String TAG = "cr_MainActivity"; | 31 private static final String TAG = "cr_MainActivity"; |
| 27 | 32 |
| 28 /** | 33 /** |
| 29 * Name of class which launches browser in WebAPK mode. | 34 * Name of class which launches browser in WebAPK mode. |
| 30 */ | 35 */ |
| 31 private static final String HOST_BROWSER_LAUNCHER_CLASS_NAME = | 36 private static final String HOST_BROWSER_LAUNCHER_CLASS_NAME = |
| 32 "org.chromium.webapk.lib.runtime_library.HostBrowserLauncher"; | 37 "org.chromium.webapk.lib.runtime_library.HostBrowserLauncher"; |
| 33 | 38 |
| 34 // Action for launching {@link WebappLauncherActivity}. Must stay in sync wi th | 39 // Action for launching {@link WebappLauncherActivity}. Must stay in sync wi th |
| 35 // {@link WebappLauncherActivity#ACTION_START_WEBAPP}. | 40 // {@link WebappLauncherActivity#ACTION_START_WEBAPP}. |
| 36 public static final String ACTION_START_WEBAPK = | 41 public static final String ACTION_START_WEBAPK = |
| 37 "com.google.android.apps.chrome.webapps.WebappManager.ACTION_START_W EBAPP"; | 42 "com.google.android.apps.chrome.webapps.WebappManager.ACTION_START_W EBAPP"; |
| 38 | 43 |
| 39 // Must stay in sync with | 44 // Must stay in sync with |
| 40 // {@link org.chromium.chrome.browser.ShortcutHelper#REUSE_URL_MATCHING_TAB_ ELSE_NEW_TAB}. | 45 // {@link org.chromium.chrome.browser.ShortcutHelper#REUSE_URL_MATCHING_TAB_ ELSE_NEW_TAB}. |
| 41 private static final String REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB = | 46 private static final String REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB = |
| 42 "REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB"; | 47 "REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB"; |
| 43 | 48 |
| 44 /** | 49 /** |
| 45 * Key for passing app icon id. | 50 * Key for passing app icon id. |
| 46 */ | 51 */ |
| 47 private static final String KEY_APP_ICON_ID = "app_icon_id"; | 52 private static final String KEY_APP_ICON_ID = "app_icon_id"; |
| 48 | 53 |
| 54 private String mOverrideUrl; | |
| 55 private String mStartUrl; | |
| 56 | |
| 49 /** | 57 /** |
| 50 * Creates install Intent. | 58 * Creates install Intent. |
| 51 * @param packageName Package to install. | 59 * @param packageName Package to install. |
| 52 * @return The intent. | 60 * @return The intent. |
| 53 */ | 61 */ |
| 54 public static Intent createInstallIntent(String packageName) { | 62 public static Intent createInstallIntent(String packageName) { |
| 55 String marketUrl = "market://details?id=" + packageName; | 63 String marketUrl = "market://details?id=" + packageName; |
| 56 return new Intent(Intent.ACTION_VIEW, Uri.parse(marketUrl)); | 64 return new Intent(Intent.ACTION_VIEW, Uri.parse(marketUrl)); |
| 57 } | 65 } |
| 58 | 66 |
| 59 @Override | 67 @Override |
| 60 protected void onCreate(Bundle savedInstanceState) { | 68 protected void onCreate(Bundle savedInstanceState) { |
| 61 super.onCreate(savedInstanceState); | 69 super.onCreate(savedInstanceState); |
| 62 launch(); | 70 mOverrideUrl = getOverrideUrl(); |
| 63 finish(); | 71 mStartUrl = (mOverrideUrl != null) ? mOverrideUrl : getStartUrl(); |
| 64 } | 72 if (mStartUrl == null) { |
| 65 | 73 finish(); |
| 66 /** | |
| 67 * Launches WebAPK. | |
| 68 */ | |
| 69 private void launch() { | |
| 70 String overrideUrl = getOverrideUrl(); | |
| 71 String startUrl = (overrideUrl != null) ? overrideUrl : getStartUrl(); | |
| 72 if (startUrl == null) { | |
| 73 return; | 74 return; |
| 74 } | 75 } |
| 75 | 76 |
| 76 if (launchHostBrowserInWebApkMode(startUrl, overrideUrl)) { | 77 Log.v(TAG, "Url of the WebAPK: " + mStartUrl); |
| 77 return; | |
| 78 } | |
| 79 if (launchBrowser(startUrl)) { | |
| 80 return; | |
| 81 } | |
| 82 installBrowser(); | |
| 83 } | |
| 84 | |
| 85 /** | |
| 86 * Launches host browser in WebAPK mode. | |
| 87 * @return True if successful. | |
| 88 */ | |
| 89 private boolean launchHostBrowserInWebApkMode(String startUrl, String overri deUrl) { | |
| 90 Log.v(TAG, "Url of the WebAPK: " + startUrl); | |
| 91 String packageName = getPackageName(); | 78 String packageName = getPackageName(); |
| 92 Log.v(TAG, "Package name of the WebAPK:" + packageName); | 79 Log.v(TAG, "Package name of the WebAPK:" + packageName); |
| 93 | 80 |
| 94 String runtimeHost = WebApkUtils.getHostBrowserPackageName(this); | 81 String runtimeHost = WebApkUtils.getHostBrowserPackageName(this); |
| 82 if (!TextUtils.isEmpty(runtimeHost) && launchInHostBrowser(runtimeHost)) { | |
| 83 finish(); | |
| 84 return; | |
| 85 } | |
| 86 | |
| 87 String hostUrl = ""; | |
| 88 try { | |
| 89 hostUrl = new URL(mStartUrl).getHost(); | |
| 90 } catch (MalformedURLException e) { | |
| 91 Log.e(TAG, "Invalid URL of the WebApk."); | |
| 92 finish(); | |
| 93 return; | |
| 94 } | |
|
pkotwicz
2017/05/26 22:38:39
Don't you need to call WebApkUtils#deleteSharedPre
Xi Han
2017/05/29 21:18:56
You are right. Call it inside launchiInHostBrowser
| |
| 95 DialogFragment dialogFragment = ChooseHostBrowserDialogFragment.newInsta nce(hostUrl); | |
| 96 dialogFragment.show(getSupportFragmentManager(), "ChooseHostBrowserDialo gFragment"); | |
| 97 } | |
| 98 | |
| 99 /** Retrieves URL from the intent's data. Returns null if a URL could not be retrieved. */ | |
| 100 private String getOverrideUrl() { | |
| 101 String overrideUrl = getIntent().getDataString(); | |
| 102 if (overrideUrl != null && overrideUrl.startsWith("https:")) { | |
| 103 return overrideUrl; | |
| 104 } | |
| 105 return null; | |
| 106 } | |
| 107 | |
| 108 /** Returns the start URL from the Android Manifest. */ | |
| 109 private String getStartUrl() { | |
| 110 ApplicationInfo appInfo; | |
| 111 try { | |
| 112 appInfo = getPackageManager().getApplicationInfo( | |
| 113 getPackageName(), PackageManager.GET_META_DATA); | |
| 114 } catch (NameNotFoundException e) { | |
| 115 return null; | |
| 116 } | |
| 117 return appInfo.metaData.getString(WebApkMetaDataKeys.START_URL); | |
| 118 } | |
| 119 | |
| 120 @Override | |
| 121 public void onHostBrowserSelected(String runtimeHost) { | |
| 122 Set<String> installedBrowsers = WebApkUtils.getInstalledBrowsers(getPack ageManager()); | |
| 123 if (installedBrowsers.contains(runtimeHost)) { | |
| 124 launchInHostBrowser(runtimeHost); | |
| 125 } else { | |
| 126 installBrowser(runtimeHost); | |
| 127 } | |
|
pkotwicz
2017/05/26 22:38:39
Don't you need to call WebApkUtils#deleteSharedPre
Xi Han
2017/05/29 21:18:55
Add a call in |launchInHostBrowser|.
| |
| 128 // It is safe to cache the runtimeHost to the share pref if user didn't install the browser | |
| 129 // in {@link installBrowser}. On next launch, | |
| 130 // {@link WebApkUtils#getHostBrowserPackageName()} will catch it, and th e dialog to choose | |
| 131 // host browser will show again. If user did install the browser chosen, saving the | |
| 132 // runtimeHost to the shared pref can avoid showing the dialog. | |
| 133 WebApkUtils.writeHostBrowserToSharedPref(this, runtimeHost); | |
| 134 finish(); | |
| 135 } | |
| 136 | |
| 137 @Override | |
| 138 public void onQuit() { | |
| 139 finish(); | |
| 140 } | |
| 141 | |
| 142 private boolean launchInHostBrowser(String runtimeHost) { | |
| 95 boolean forceNavigation = false; | 143 boolean forceNavigation = false; |
| 96 int source = getIntent().getIntExtra(WebApkConstants.EXTRA_SOURCE, 0); | 144 int source = getIntent().getIntExtra(WebApkConstants.EXTRA_SOURCE, 0); |
| 97 if (overrideUrl != null) { | 145 if (mOverrideUrl != null) { |
| 98 if (source == WebApkConstants.SHORTCUT_SOURCE_UNKNOWN) { | 146 if (source == WebApkConstants.SHORTCUT_SOURCE_UNKNOWN) { |
| 99 source = WebApkConstants.SHORTCUT_SOURCE_EXTERNAL_INTENT; | 147 source = WebApkConstants.SHORTCUT_SOURCE_EXTERNAL_INTENT; |
| 100 } | 148 } |
| 101 forceNavigation = getIntent().getBooleanExtra( | 149 forceNavigation = getIntent().getBooleanExtra( |
| 102 WebApkConstants.EXTRA_WEBAPK_FORCE_NAVIGATION, true); | 150 WebApkConstants.EXTRA_WEBAPK_FORCE_NAVIGATION, true); |
| 103 } | 151 } |
| 104 | 152 |
| 105 // The override URL is non null when the WebAPK is launched from a deep link. The WebAPK | 153 // The override URL is non null when the WebAPK is launched from a deep link. The WebAPK |
| 106 // should navigate to the URL in the deep link even if the WebAPK is alr eady open. | 154 // should navigate to the URL in the deep link even if the WebAPK is alr eady open. |
| 107 Intent intent = new Intent(); | 155 Intent intent = new Intent(); |
| 108 intent.setAction(ACTION_START_WEBAPK); | 156 intent.setAction(ACTION_START_WEBAPK); |
| 109 intent.setPackage(runtimeHost); | 157 intent.setPackage(runtimeHost); |
| 110 intent.putExtra(WebApkConstants.EXTRA_URL, startUrl) | 158 intent.putExtra(WebApkConstants.EXTRA_URL, mStartUrl) |
| 111 .putExtra(WebApkConstants.EXTRA_SOURCE, source) | 159 .putExtra(WebApkConstants.EXTRA_SOURCE, source) |
| 112 .putExtra(WebApkConstants.EXTRA_WEBAPK_PACKAGE_NAME, packageName ) | 160 .putExtra(WebApkConstants.EXTRA_WEBAPK_PACKAGE_NAME, getPackageN ame()) |
| 113 .putExtra(WebApkConstants.EXTRA_WEBAPK_FORCE_NAVIGATION, forceNa vigation); | 161 .putExtra(WebApkConstants.EXTRA_WEBAPK_FORCE_NAVIGATION, forceNa vigation); |
| 114 | 162 |
| 115 try { | 163 try { |
| 116 startActivity(intent); | 164 startActivity(intent); |
| 117 return true; | 165 return true; |
| 118 } catch (ActivityNotFoundException e) { | 166 } catch (ActivityNotFoundException e) { |
| 119 Log.w(TAG, "Unable to launch browser in WebAPK mode."); | 167 Log.w(TAG, "Unable to launch browser in WebAPK mode."); |
| 120 e.printStackTrace(); | 168 e.printStackTrace(); |
| 121 return false; | 169 return false; |
| 122 } | 170 } |
| 123 } | 171 } |
| 124 | 172 |
| 125 /** | 173 /** |
| 126 * Launches browser (not necessarily the host browser). | |
| 127 * @param startUrl URL to navigate browser to. | |
| 128 * @return True if successful. | |
| 129 */ | |
| 130 private boolean launchBrowser(String startUrl) { | |
| 131 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(startUrl)); | |
| 132 intent.addCategory(Intent.CATEGORY_BROWSABLE); | |
| 133 | |
| 134 // The WebAPK can handle {@link startUrl}. Set a selector to prevent the WebAPK from | |
| 135 // launching itself. | |
| 136 try { | |
| 137 Intent selectorIntent = Intent.parseUri("https://", Intent.URI_INTEN T_SCHEME); | |
| 138 intent.setSelector(selectorIntent); | |
| 139 } catch (URISyntaxException e) { | |
| 140 return false; | |
| 141 } | |
| 142 | |
| 143 // Add extras in case that the URL is launched in Chrome. | |
| 144 int source = | |
| 145 getIntent().getIntExtra(WebApkConstants.EXTRA_SOURCE, Intent.URI _INTENT_SCHEME); | |
| 146 intent.putExtra(REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB, true) | |
| 147 .putExtra(WebApkConstants.EXTRA_SOURCE, source); | |
| 148 | |
| 149 try { | |
| 150 startActivity(intent); | |
| 151 } catch (ActivityNotFoundException e) { | |
| 152 return false; | |
| 153 } | |
| 154 return true; | |
| 155 } | |
| 156 | |
| 157 /** | |
| 158 * Launches the Play Store with the host browser's page. | 174 * Launches the Play Store with the host browser's page. |
| 159 */ | 175 */ |
| 160 private void installBrowser() { | 176 private void installBrowser(String hostBrowserPackageName) { |
| 161 String hostBrowserPackageName = WebApkUtils.getHostBrowserPackageName(th is); | |
| 162 if (hostBrowserPackageName == null) { | |
| 163 return; | |
| 164 } | |
| 165 | |
| 166 try { | 177 try { |
| 167 startActivity(createInstallIntent(hostBrowserPackageName)); | 178 startActivity(createInstallIntent(hostBrowserPackageName)); |
| 168 } catch (ActivityNotFoundException e) { | 179 } catch (ActivityNotFoundException e) { |
| 169 } | 180 } |
| 170 } | 181 } |
| 171 | |
| 172 /** Retrieves URL from the intent's data. Returns null if a URL could not be retrieved. */ | |
| 173 private String getOverrideUrl() { | |
| 174 String overrideUrl = getIntent().getDataString(); | |
| 175 if (overrideUrl != null && overrideUrl.startsWith("https:")) { | |
| 176 return overrideUrl; | |
| 177 } | |
| 178 return null; | |
| 179 } | |
| 180 | |
| 181 /** Returns the start URL from the Android Manifest. */ | |
| 182 private String getStartUrl() { | |
| 183 ApplicationInfo appInfo; | |
| 184 try { | |
| 185 appInfo = getPackageManager().getApplicationInfo( | |
| 186 getPackageName(), PackageManager.GET_META_DATA); | |
| 187 } catch (NameNotFoundException e) { | |
| 188 return null; | |
| 189 } | |
| 190 return appInfo.metaData.getString(WebApkMetaDataKeys.START_URL); | |
| 191 } | |
| 192 } | 182 } |
| OLD | NEW |