1// Copyright 2013 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.chrome.browser; 6 7import android.app.ActivityManager; 8import android.content.Context; 9import android.content.Intent; 10import android.graphics.Bitmap; 11import android.text.TextUtils; 12import android.util.Base64; 13import android.util.Log; 14 15import org.chromium.base.CalledByNative; 16import org.chromium.content_public.common.ScreenOrientationConstants; 17 18import java.io.ByteArrayOutputStream; 19import java.util.UUID; 20 21/** 22 * This is a helper class to create shortcuts on the Android home screen. 23 */ 24public class ShortcutHelper { 25 public static final String EXTRA_ICON = "org.chromium.chrome.browser.webapp_icon"; 26 public static final String EXTRA_ID = "org.chromium.chrome.browser.webapp_id"; 27 public static final String EXTRA_MAC = "org.chromium.chrome.browser.webapp_mac"; 28 public static final String EXTRA_TITLE = "org.chromium.chrome.browser.webapp_title"; 29 public static final String EXTRA_URL = "org.chromium.chrome.browser.webapp_url"; 30 public static final String EXTRA_ORIENTATION = ScreenOrientationConstants.EXTRA_ORIENTATION; 31 32 private static String sFullScreenAction; 33 34 /** 35 * Sets the class name used when launching the shortcuts. 36 * @param fullScreenAction Class name of the fullscreen Activity. 37 */ 38 public static void setFullScreenAction(String fullScreenAction) { 39 sFullScreenAction = fullScreenAction; 40 } 41 42 /** 43 * Callback to be passed to the initialized() method. 44 */ 45 public interface OnInitialized { 46 public void onInitialized(String title); 47 } 48 49 private final Context mAppContext; 50 private final Tab mTab; 51 52 private OnInitialized mCallback; 53 private boolean mIsInitialized; 54 private long mNativeShortcutHelper; 55 56 public ShortcutHelper(Context appContext, Tab tab) { 57 mAppContext = appContext; 58 mTab = tab; 59 } 60 61 /** 62 * Gets all the information required to initialize the UI, the passed 63 * callback will be run when those information will be available. 64 * @param callback Callback to be run when initialized. 65 */ 66 public void initialize(OnInitialized callback) { 67 mCallback = callback; 68 mNativeShortcutHelper = nativeInitialize(mTab.getNativePtr()); 69 } 70 71 /** 72 * Returns whether the object is initialized. 73 */ 74 public boolean isInitialized() { 75 return mIsInitialized; 76 } 77 78 /** 79 * Puts the object in a state where it is safe to be destroyed. 80 */ 81 public void tearDown() { 82 nativeTearDown(mNativeShortcutHelper); 83 84 // Make sure the callback isn't run if the tear down happens before 85 // onInitialized() is called. 86 mCallback = null; 87 mNativeShortcutHelper = 0; 88 } 89 90 @CalledByNative 91 private void onInitialized(String title) { 92 mIsInitialized = true; 93 94 if (mCallback != null) { 95 mCallback.onInitialized(title); 96 } 97 } 98 99 /** 100 * Adds a shortcut for the current Tab. 101 * @param userRequestedTitle Updated title for the shortcut. 102 */ 103 public void addShortcut(String userRequestedTitle) { 104 if (TextUtils.isEmpty(sFullScreenAction)) { 105 Log.e("ShortcutHelper", "ShortcutHelper is uninitialized. Aborting."); 106 return; 107 } 108 ActivityManager am = (ActivityManager) mAppContext.getSystemService( 109 Context.ACTIVITY_SERVICE); 110 nativeAddShortcut(mNativeShortcutHelper, userRequestedTitle, am.getLauncherLargeIconSize()); 111 112 // The C++ instance is no longer owned by the Java object. 113 mCallback = null; 114 mNativeShortcutHelper = 0; 115 } 116 117 /** 118 * Called when we have to fire an Intent to add a shortcut to the homescreen. 119 * If the webpage indicated that it was capable of functioning as a webapp, it is added as a 120 * shortcut to a webapp Activity rather than as a general bookmark. User is sent to the 121 * homescreen as soon as the shortcut is created. 122 */ 123 @SuppressWarnings("unused") 124 @CalledByNative 125 private static void addShortcut(Context context, String url, String title, Bitmap icon, 126 int red, int green, int blue, boolean isWebappCapable, int orientation) { 127 assert sFullScreenAction != null; 128 129 Intent shortcutIntent; 130 if (isWebappCapable) { 131 // Encode the icon as a base64 string (Launcher drops Bitmaps in the Intent). 132 String encodedIcon = ""; 133 if (icon != null) { 134 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 135 icon.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream); 136 byte[] byteArray = byteArrayOutputStream.toByteArray(); 137 encodedIcon = Base64.encodeToString(byteArray, Base64.DEFAULT); 138 } 139 140 // Add the shortcut as a launcher icon for a full-screen Activity. 141 shortcutIntent = new Intent(); 142 shortcutIntent.setAction(sFullScreenAction); 143 shortcutIntent.putExtra(EXTRA_ICON, encodedIcon); 144 shortcutIntent.putExtra(EXTRA_ID, UUID.randomUUID().toString()); 145 shortcutIntent.putExtra(EXTRA_TITLE, title); 146 shortcutIntent.putExtra(EXTRA_URL, url); 147 shortcutIntent.putExtra(EXTRA_ORIENTATION, orientation); 148 149 // The only reason we convert to a String here is because Android inexplicably eats a 150 // byte[] when adding the shortcut -- the Bundle received by the launched Activity even 151 // lacks the key for the extra. 152 byte[] mac = WebappAuthenticator.getMacForUrl(context, url); 153 String encodedMac = Base64.encodeToString(mac, Base64.DEFAULT); 154 shortcutIntent.putExtra(EXTRA_MAC, encodedMac); 155 } else { 156 // Add the shortcut as a launcher icon to open in the browser Activity. 157 shortcutIntent = BookmarkUtils.createShortcutIntent(context, url); 158 } 159 160 shortcutIntent.setPackage(context.getPackageName()); 161 context.sendBroadcast(BookmarkUtils.createAddToHomeIntent(context, shortcutIntent, title, 162 icon, red, green, blue)); 163 164 // User is sent to the homescreen as soon as the shortcut is created. 165 Intent homeIntent = new Intent(Intent.ACTION_MAIN); 166 homeIntent.addCategory(Intent.CATEGORY_HOME); 167 homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 168 context.startActivity(homeIntent); 169 } 170 171 private native long nativeInitialize(long tabAndroidPtr); 172 private native void nativeAddShortcut(long nativeShortcutHelper, String userRequestedTitle, 173 int launcherLargeIconSize); 174 private native void nativeTearDown(long nativeShortcutHelper); 175} 176