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 | |
57 // A dialog that asks user to choose runtime host to launch this WebAPK. | |
58 private DialogFragment mDialog; | |
49 /** | 59 /** |
50 * Creates install Intent. | 60 * Creates install Intent. |
51 * @param packageName Package to install. | 61 * @param packageName Package to install. |
52 * @return The intent. | 62 * @return The intent. |
53 */ | 63 */ |
54 public static Intent createInstallIntent(String packageName) { | 64 public static Intent createInstallIntent(String packageName) { |
55 String marketUrl = "market://details?id=" + packageName; | 65 String marketUrl = "market://details?id=" + packageName; |
56 return new Intent(Intent.ACTION_VIEW, Uri.parse(marketUrl)); | 66 return new Intent(Intent.ACTION_VIEW, Uri.parse(marketUrl)); |
57 } | 67 } |
58 | 68 |
59 @Override | 69 @Override |
60 protected void onCreate(Bundle savedInstanceState) { | 70 protected void onCreate(Bundle savedInstanceState) { |
61 super.onCreate(savedInstanceState); | 71 super.onCreate(savedInstanceState); |
62 launch(); | 72 launch(); |
pkotwicz
2017/05/24 04:19:29
I don't think that having a separate launch() func
Xi Han
2017/05/24 16:52:37
Agree, deleted.
| |
63 finish(); | |
64 } | 73 } |
65 | 74 |
66 /** | 75 /** |
67 * Launches WebAPK. | 76 * Launches WebAPK. |
68 */ | 77 */ |
69 private void launch() { | 78 private void launch() { |
70 String overrideUrl = getOverrideUrl(); | 79 mOverrideUrl = getOverrideUrl(); |
71 String startUrl = (overrideUrl != null) ? overrideUrl : getStartUrl(); | 80 mStartUrl = (mOverrideUrl != null) ? mOverrideUrl : getStartUrl(); |
72 if (startUrl == null) { | 81 if (mStartUrl == null) { |
82 finish(); | |
73 return; | 83 return; |
74 } | 84 } |
75 | 85 |
76 if (launchHostBrowserInWebApkMode(startUrl, overrideUrl)) { | 86 launchHostBrowserInWebApkMode(); |
77 return; | |
78 } | |
79 if (launchBrowser(startUrl)) { | |
80 return; | |
81 } | |
82 installBrowser(); | |
83 } | 87 } |
84 | 88 |
85 /** | 89 /** |
86 * Launches host browser in WebAPK mode. | 90 * Launches host browser in WebAPK mode. |
87 * @return True if successful. | 91 * @return True if successful. |
88 */ | 92 */ |
89 private boolean launchHostBrowserInWebApkMode(String startUrl, String overri deUrl) { | 93 private void launchHostBrowserInWebApkMode() { |
pkotwicz
2017/05/24 04:19:29
I think that it now makes sense to merge this func
Xi Han
2017/05/24 16:52:37
Acknowledged.
| |
90 Log.v(TAG, "Url of the WebAPK: " + startUrl); | 94 Log.v(TAG, "Url of the WebAPK: " + mStartUrl); |
91 String packageName = getPackageName(); | 95 String packageName = getPackageName(); |
92 Log.v(TAG, "Package name of the WebAPK:" + packageName); | 96 Log.v(TAG, "Package name of the WebAPK:" + packageName); |
93 | 97 |
94 String runtimeHost = WebApkUtils.getHostBrowserPackageName(this); | 98 String runtimeHost = WebApkUtils.getHostBrowserPackageName(this); |
95 boolean isFromExternalIntent = (overrideUrl != null); | 99 if (!TextUtils.isEmpty(runtimeHost) && launchInHostBrowser(runtimeHost)) { |
100 finish(); | |
101 } else { | |
pkotwicz
2017/05/24 04:19:29
My preference is to make the try/catch statement a
Xi Han
2017/05/24 16:52:37
Done.
| |
102 try { | |
103 mDialog = ChooseHostBrowserDialogFragment.newInstance(new URL(mS tartUrl).getHost()); | |
104 mDialog.show(getSupportFragmentManager(), "ChooseHostBrowserDial ogFragment"); | |
105 } catch (MalformedURLException e) { | |
106 Log.e(TAG, "Unable to create a dialog to choose the host browser ."); | |
107 finish(); | |
108 } | |
109 } | |
110 } | |
111 | |
112 /** Retrieves URL from the intent's data. Returns null if a URL could not be retrieved. */ | |
113 private String getOverrideUrl() { | |
114 String overrideUrl = getIntent().getDataString(); | |
115 if (overrideUrl != null && overrideUrl.startsWith("https:")) { | |
116 return overrideUrl; | |
117 } | |
118 return null; | |
119 } | |
120 | |
121 /** Returns the start URL from the Android Manifest. */ | |
122 private String getStartUrl() { | |
123 ApplicationInfo appInfo; | |
124 try { | |
125 appInfo = getPackageManager().getApplicationInfo( | |
126 getPackageName(), PackageManager.GET_META_DATA); | |
127 } catch (NameNotFoundException e) { | |
128 return null; | |
129 } | |
130 return appInfo.metaData.getString(WebApkMetaDataKeys.START_URL); | |
131 } | |
132 | |
133 @Override | |
134 public void onHostBrowserSelected(String runtimeHost) { | |
135 Set<String> installedBrowsers = WebApkUtils.getInstalledBrowsers(getPack ageManager()); | |
136 if (installedBrowsers.contains(runtimeHost)) { | |
137 launchInHostBrowser(runtimeHost); | |
138 } else { | |
139 installBrowser(runtimeHost); | |
140 } | |
141 // It is safe to cache the runtimeHost to the share pref if user didn't install the browser | |
142 // in {@link installBrowser}. On next launch, {@link WebApkUtils#getHost BrowserPackageName} | |
143 // will catch it, and the dialog to choose host browser will show again. If user did install | |
144 // the browser chosen, saving the runtimeHost to the shared pref can avo id the dialog to | |
145 // show. | |
146 WebApkUtils.writeHostBrowserToSharedPref(this, runtimeHost); | |
147 finish(); | |
148 } | |
149 | |
150 @Override | |
151 public void onQuit() { | |
152 finish(); | |
153 } | |
154 | |
155 private boolean launchInHostBrowser(String runtimeHost) { | |
156 boolean isFromExternalIntent = (mOverrideUrl != null); | |
96 int source = getIntent().getIntExtra(WebApkConstants.EXTRA_SOURCE, 0); | 157 int source = getIntent().getIntExtra(WebApkConstants.EXTRA_SOURCE, 0); |
97 if (isFromExternalIntent && source == WebApkConstants.SHORTCUT_SOURCE_UN KNOWN) { | 158 if (isFromExternalIntent && source == WebApkConstants.SHORTCUT_SOURCE_UN KNOWN) { |
98 source = WebApkConstants.SHORTCUT_SOURCE_EXTERNAL_INTENT; | 159 source = WebApkConstants.SHORTCUT_SOURCE_EXTERNAL_INTENT; |
99 } | 160 } |
100 | 161 |
101 // The override URL is non null when the WebAPK is launched from a deep link. The WebAPK | 162 // The override URL is non null when the WebAPK is launched from a deep link. The WebAPK |
102 // should navigate to the URL in the deep link even if the WebAPK is alr eady open. | 163 // should navigate to the URL in the deep link even if the WebAPK is alr eady open. |
103 Intent intent = new Intent(); | 164 Intent intent = new Intent(); |
104 intent.setAction(ACTION_START_WEBAPK); | 165 intent.setAction(ACTION_START_WEBAPK); |
105 intent.setPackage(runtimeHost); | 166 intent.setPackage(runtimeHost); |
106 intent.putExtra(WebApkConstants.EXTRA_URL, startUrl) | 167 intent.putExtra(WebApkConstants.EXTRA_URL, mStartUrl) |
107 .putExtra(WebApkConstants.EXTRA_SOURCE, source) | 168 .putExtra(WebApkConstants.EXTRA_SOURCE, source) |
108 .putExtra(WebApkConstants.EXTRA_WEBAPK_PACKAGE_NAME, packageName ) | 169 .putExtra(WebApkConstants.EXTRA_WEBAPK_PACKAGE_NAME, getPackageN ame()) |
109 .putExtra(WebApkConstants.EXTRA_WEBAPK_FORCE_NAVIGATION, isFromE xternalIntent); | 170 .putExtra(WebApkConstants.EXTRA_WEBAPK_FORCE_NAVIGATION, isFromE xternalIntent); |
110 | 171 |
111 try { | 172 try { |
112 startActivity(intent); | 173 startActivity(intent); |
113 return true; | 174 return true; |
114 } catch (ActivityNotFoundException e) { | 175 } catch (ActivityNotFoundException e) { |
115 Log.w(TAG, "Unable to launch browser in WebAPK mode."); | 176 Log.w(TAG, "Unable to launch browser in WebAPK mode."); |
116 e.printStackTrace(); | 177 e.printStackTrace(); |
117 return false; | 178 return false; |
118 } | 179 } |
119 } | 180 } |
120 | 181 |
121 /** | 182 /** |
122 * Launches browser (not necessarily the host browser). | |
123 * @param startUrl URL to navigate browser to. | |
124 * @return True if successful. | |
125 */ | |
126 private boolean launchBrowser(String startUrl) { | |
127 Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(startUrl)); | |
128 intent.addCategory(Intent.CATEGORY_BROWSABLE); | |
129 | |
130 // The WebAPK can handle {@link startUrl}. Set a selector to prevent the WebAPK from | |
131 // launching itself. | |
132 try { | |
133 Intent selectorIntent = Intent.parseUri("https://", Intent.URI_INTEN T_SCHEME); | |
134 intent.setSelector(selectorIntent); | |
135 } catch (URISyntaxException e) { | |
136 return false; | |
137 } | |
138 | |
139 // Add extras in case that the URL is launched in Chrome. | |
140 int source = | |
141 getIntent().getIntExtra(WebApkConstants.EXTRA_SOURCE, Intent.URI _INTENT_SCHEME); | |
142 intent.putExtra(REUSE_URL_MATCHING_TAB_ELSE_NEW_TAB, true) | |
143 .putExtra(WebApkConstants.EXTRA_SOURCE, source); | |
144 | |
145 try { | |
146 startActivity(intent); | |
147 } catch (ActivityNotFoundException e) { | |
148 return false; | |
149 } | |
150 return true; | |
151 } | |
152 | |
153 /** | |
154 * Launches the Play Store with the host browser's page. | 183 * Launches the Play Store with the host browser's page. |
155 */ | 184 */ |
156 private void installBrowser() { | 185 private void installBrowser(String hostBrowserPackageName) { |
157 String hostBrowserPackageName = WebApkUtils.getHostBrowserPackageName(th is); | |
158 if (hostBrowserPackageName == null) { | |
159 return; | |
160 } | |
161 | |
162 try { | 186 try { |
163 startActivity(createInstallIntent(hostBrowserPackageName)); | 187 startActivity(createInstallIntent(hostBrowserPackageName)); |
164 } catch (ActivityNotFoundException e) { | 188 } catch (ActivityNotFoundException e) { |
165 } | 189 } |
166 } | 190 } |
167 | |
168 /** Retrieves URL from the intent's data. Returns null if a URL could not be retrieved. */ | |
169 private String getOverrideUrl() { | |
170 String overrideUrl = getIntent().getDataString(); | |
171 if (overrideUrl != null && overrideUrl.startsWith("https:")) { | |
172 return overrideUrl; | |
173 } | |
174 return null; | |
175 } | |
176 | |
177 /** Returns the start URL from the Android Manifest. */ | |
178 private String getStartUrl() { | |
179 ApplicationInfo appInfo; | |
180 try { | |
181 appInfo = getPackageManager().getApplicationInfo( | |
182 getPackageName(), PackageManager.GET_META_DATA); | |
183 } catch (NameNotFoundException e) { | |
184 return null; | |
185 } | |
186 return appInfo.metaData.getString(WebApkMetaDataKeys.START_URL); | |
187 } | |
188 } | 191 } |
OLD | NEW |