| 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; | 7 import android.app.Activity; |
| 8 import android.content.ComponentName; | 8 import android.content.Context; |
| 9 import android.content.Intent; | 9 import android.content.Intent; |
| 10 import android.content.pm.ApplicationInfo; | |
| 11 import android.content.pm.PackageManager; | |
| 12 import android.content.pm.PackageManager.NameNotFoundException; | |
| 13 import android.graphics.Bitmap; | |
| 14 import android.graphics.BitmapFactory; | |
| 15 import android.os.Bundle; | 10 import android.os.Bundle; |
| 16 import android.text.TextUtils; | |
| 17 import android.util.Base64; | |
| 18 import android.util.Log; | 11 import android.util.Log; |
| 19 | 12 |
| 20 import org.chromium.webapk.lib.common.WebApkConstants; | 13 import java.lang.reflect.Method; |
| 21 | |
| 22 import java.io.ByteArrayOutputStream; | |
| 23 | 14 |
| 24 /** | 15 /** |
| 25 * WebAPK's main Activity. | 16 * WebAPK's main Activity. |
| 26 */ | 17 */ |
| 27 public class MainActivity extends Activity { | 18 public class MainActivity extends Activity { |
| 28 // These EXTRA_* values must stay in sync with | 19 private static final String TAG = "cr_MainActivity"; |
| 29 // {@link org.chromium.chrome.browser.ShortcutHelper}. | |
| 30 private static final String EXTRA_ID = "org.chromium.chrome.browser.webapp_i
d"; | |
| 31 private static final String EXTRA_ICON = "org.chromium.chrome.browser.webapp
_icon"; | |
| 32 private static final String EXTRA_SHORT_NAME = "org.chromium.chrome.browser.
webapp_short_name"; | |
| 33 private static final String EXTRA_NAME = "org.chromium.chrome.browser.webapp
_name"; | |
| 34 private static final String EXTRA_URL = "org.chromium.chrome.browser.webapp_
url"; | |
| 35 private static final String EXTRA_SOURCE = "org.chromium.chrome.browser.weba
pp_source"; | |
| 36 private static final String EXTRA_THEME_COLOR = "org.chromium.chrome.browser
.theme_color"; | |
| 37 private static final String EXTRA_BACKGROUND_COLOR = | |
| 38 "org.chromium.chrome.browser.background_color"; | |
| 39 private static final String EXTRA_IS_ICON_GENERATED = | |
| 40 "org.chromium.chrome.browser.is_icon_generated"; | |
| 41 private static final String EXTRA_WEBAPK_PACKAGE_NAME = | |
| 42 "org.chromium.chrome.browser.webapk_package_name"; | |
| 43 | 20 |
| 44 private static final String META_DATA_RUNTIME_HOST = "runtimeHost"; | 21 /** |
| 45 private static final String META_DATA_START_URL = "startUrl"; | 22 * Name of class which launches browser in WebAPK mode. |
| 46 private static final String META_DATA_NAME = "name"; | 23 */ |
| 47 private static final String META_DATA_DISPLAY_MODE = "displayMode"; | 24 private static final String HOST_BROWSER_LAUNCHER_CLASS_NAME = |
| 48 private static final String META_DATA_ORIENTATION = "orientation"; | 25 "org.chromium.webapk.lib.runtime_library.HostBrowserLauncher"; |
| 49 private static final String META_DATA_THEME_COLOR = "themeColor"; | |
| 50 private static final String META_DATA_BACKGROUND_COLOR = "backgroundColor"; | |
| 51 private static final String META_DATA_ICON_URL = "iconUrl"; | |
| 52 | 26 |
| 53 private static final String TAG = "cr_MainActivity"; | 27 /** |
| 28 * Key for passing app icon id. |
| 29 */ |
| 30 private static final String KEY_APP_ICON_ID = "app_icon_id"; |
| 54 | 31 |
| 55 @Override | 32 @Override |
| 56 protected void onCreate(Bundle savedInstanceState) { | 33 protected void onCreate(Bundle savedInstanceState) { |
| 57 super.onCreate(savedInstanceState); | 34 super.onCreate(savedInstanceState); |
| 35 launchHostBrowser(); |
| 36 finish(); |
| 37 } |
| 58 | 38 |
| 59 String packageName = getPackageName(); | 39 /** |
| 40 * Launches host browser in WebAPK mode. |
| 41 */ |
| 42 public void launchHostBrowser() { |
| 43 ClassLoader webApkClassLoader = HostBrowserClassLoader.getClassLoaderIns
tance( |
| 44 this, HOST_BROWSER_LAUNCHER_CLASS_NAME); |
| 45 if (webApkClassLoader == null) { |
| 46 Log.w(TAG, "Unable to create ClassLoader."); |
| 47 return; |
| 48 } |
| 49 |
| 60 try { | 50 try { |
| 61 ApplicationInfo appInfo = getPackageManager().getApplicationInfo( | 51 Class<?> hostBrowserLauncherClass = |
| 62 packageName, PackageManager.GET_META_DATA); | 52 webApkClassLoader.loadClass(HOST_BROWSER_LAUNCHER_CLASS_NAME
); |
| 63 Bundle bundle = appInfo.metaData; | 53 Method launchMethod = hostBrowserLauncherClass.getMethod( |
| 64 String url = bundle.getString(META_DATA_START_URL); | 54 "launch", Context.class, Intent.class, Bundle.class); |
| 65 | 55 Object hostBrowserLauncherInstance = hostBrowserLauncherClass.newIns
tance(); |
| 66 Intent intent = getIntent(); | 56 Bundle bundle = new Bundle(); |
| 67 String overrideUrl = intent.getDataString(); | 57 bundle.putInt(KEY_APP_ICON_ID, R.drawable.app_icon); |
| 68 // TODO(pkotwicz): Use same logic as {@code IntentHandler#shouldIgno
reIntent()} | 58 launchMethod.invoke(hostBrowserLauncherInstance, this, getIntent(),
bundle); |
| 69 if (overrideUrl != null && overrideUrl.startsWith("https:")) { | 59 } catch (Exception e) { |
| 70 url = overrideUrl; | 60 Log.w(TAG, "Unable to launch browser in WebAPK mode."); |
| 71 } | |
| 72 int source = intent.getIntExtra(EXTRA_SOURCE, 0); | |
| 73 | |
| 74 String webappId = WebApkConstants.WEBAPK_ID_PREFIX + packageName; | |
| 75 String runtimeHost = bundle.getString(META_DATA_RUNTIME_HOST); | |
| 76 String shortName = (String) getPackageManager().getApplicationLabel(
appInfo); | |
| 77 // TODO(hanxi): find a neat solution to avoid encode/decode each tim
e launch the | |
| 78 // activity. | |
| 79 Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawabl
e.app_icon); | |
| 80 String encodedIcon = encodeBitmapAsString(icon); | |
| 81 String name = bundle.getString(META_DATA_NAME); | |
| 82 String displayMode = bundle.getString(META_DATA_DISPLAY_MODE); | |
| 83 String orientation = bundle.getString(META_DATA_ORIENTATION); | |
| 84 long themeColor = getLongFromBundle(bundle, META_DATA_THEME_COLOR); | |
| 85 long backgroundColor = getLongFromBundle(bundle, META_DATA_BACKGROUN
D_COLOR); | |
| 86 boolean isIconGenerated = TextUtils.isEmpty(bundle.getString(META_DA
TA_ICON_URL)); | |
| 87 Log.v(TAG, "Url of the WebAPK: " + url); | |
| 88 Log.v(TAG, "WebappId of the WebAPK: " + webappId); | |
| 89 Log.v(TAG, "Name of the WebAPK:" + name); | |
| 90 Log.v(TAG, "Package name of the WebAPK:" + packageName); | |
| 91 | |
| 92 Intent newIntent = new Intent(); | |
| 93 newIntent.setComponent(new ComponentName(runtimeHost, | |
| 94 "org.chromium.chrome.browser.webapps.WebappLauncherActivity"
)); | |
| 95 // Chrome expects the ShortcutHelper.EXTRA_DISPLAY_MODE and | |
| 96 // ShortcutHelper.EXTRA_ORIENTATION extras to be enum values. We sen
d string extras for | |
| 97 // the display mode and orientation so have to use different keys. | |
| 98 newIntent.putExtra(EXTRA_ID, webappId) | |
| 99 .putExtra(EXTRA_SHORT_NAME, shortName) | |
| 100 .putExtra(EXTRA_NAME, name) | |
| 101 .putExtra(EXTRA_URL, url) | |
| 102 .putExtra(EXTRA_ICON, encodedIcon) | |
| 103 .putExtra(EXTRA_SOURCE, source) | |
| 104 .putExtra(EXTRA_THEME_COLOR, themeColor) | |
| 105 .putExtra(EXTRA_BACKGROUND_COLOR, backgroundColor) | |
| 106 .putExtra(EXTRA_IS_ICON_GENERATED, isIconGenerated) | |
| 107 .putExtra(EXTRA_WEBAPK_PACKAGE_NAME, packageName) | |
| 108 .putExtra(WebApkConstants.EXTRA_WEBAPK_DISPLAY_MODE, displa
yMode) | |
| 109 .putExtra(WebApkConstants.EXTRA_WEBAPK_ORIENTATION, orienta
tion); | |
| 110 startActivity(newIntent); | |
| 111 finish(); | |
| 112 } catch (NameNotFoundException e) { | |
| 113 e.printStackTrace(); | 61 e.printStackTrace(); |
| 114 } | 62 } |
| 115 } | 63 } |
| 116 | |
| 117 /** | |
| 118 * Compresses a bitmap into a PNG and converts into a Base64 encoded string. | |
| 119 * The encoded string can be decoded using {@link decodeBitmapFromString(Str
ing)}. | |
| 120 * @param bitmap The Bitmap to compress and encode. | |
| 121 * @return the String encoding the Bitmap. | |
| 122 */ | |
| 123 private static String encodeBitmapAsString(Bitmap bitmap) { | |
| 124 if (bitmap == null) return ""; | |
| 125 ByteArrayOutputStream output = new ByteArrayOutputStream(); | |
| 126 bitmap.compress(Bitmap.CompressFormat.PNG, 100, output); | |
| 127 return Base64.encodeToString(output.toByteArray(), Base64.DEFAULT); | |
| 128 } | |
| 129 | |
| 130 /** | |
| 131 * Gets a long from a Bundle. The long should be terminated with 'L'. This f
unction is more | |
| 132 * reliable than Bundle#getLong() which returns 0 if the value is below Floa
t.MAX_VALUE. | |
| 133 */ | |
| 134 private static long getLongFromBundle(Bundle bundle, String key) { | |
| 135 String value = bundle.getString(key); | |
| 136 if (value == null || !value.endsWith("L")) { | |
| 137 return 0; | |
| 138 } | |
| 139 try { | |
| 140 return Long.parseLong(value.substring(0, value.length() - 1)); | |
| 141 } catch (NumberFormatException e) { | |
| 142 } | |
| 143 return 0; | |
| 144 } | |
| 145 } | 64 } |
| OLD | NEW |