| 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.chrome.browser.customtabs; | 5 package org.chromium.chrome.browser.customtabs; |
| 6 | 6 |
| 7 import android.app.Activity; | 7 import android.app.Activity; |
| 8 import android.app.PendingIntent; | 8 import android.app.PendingIntent; |
| 9 import android.app.PendingIntent.CanceledException; | 9 import android.app.PendingIntent.CanceledException; |
| 10 import android.content.Context; | 10 import android.content.Context; |
| 11 import android.content.Intent; | 11 import android.content.Intent; |
| 12 import android.graphics.Bitmap; | 12 import android.graphics.Bitmap; |
| 13 import android.graphics.Color; | 13 import android.graphics.Color; |
| 14 import android.net.Uri; | 14 import android.net.Uri; |
| 15 import android.os.Bundle; | 15 import android.os.Bundle; |
| 16 import android.os.IBinder; |
| 17 import android.support.customtabs.CustomTabsIntent; |
| 16 import android.text.TextUtils; | 18 import android.text.TextUtils; |
| 17 import android.util.Pair; | 19 import android.util.Pair; |
| 18 | 20 |
| 19 import org.chromium.base.Log; | 21 import org.chromium.base.Log; |
| 20 import org.chromium.base.VisibleForTesting; | 22 import org.chromium.base.VisibleForTesting; |
| 21 import org.chromium.chrome.R; | 23 import org.chromium.chrome.R; |
| 22 import org.chromium.chrome.browser.util.IntentUtils; | 24 import org.chromium.chrome.browser.util.IntentUtils; |
| 23 | 25 |
| 24 import java.util.ArrayList; | 26 import java.util.ArrayList; |
| 25 import java.util.List; | 27 import java.util.List; |
| 26 | 28 |
| 27 /** | 29 /** |
| 28 * A model class that parses intent from third-party apps and provides results t
o | 30 * A model class that parses intent from third-party apps and provides results t
o |
| 29 * {@link CustomTabActivity}. | 31 * {@link CustomTabActivity}. |
| 30 */ | 32 */ |
| 31 public class CustomTabIntentDataProvider { | 33 public class CustomTabIntentDataProvider { |
| 32 private static final String TAG = "CustomTabIntentDataProvider"; | 34 private static final String TAG = "CustomTabIntentData"; |
| 33 | |
| 34 /** | |
| 35 * The category name that the service intent has to have for custom tabs. Th
is | |
| 36 * category can also be used to generically resolve to the service component
for custom tabs. | |
| 37 */ | |
| 38 public static final String CATEGORY_CUSTOM_TABS = "android.intent.category.C
USTOM_TABS"; | |
| 39 | |
| 40 /** | |
| 41 * Extra used to match the session. This has to be included in the intent to
open in | |
| 42 * a custom tab. Can be -1 if there is no session id taken. Its value is a l
ong returned | |
| 43 * by {@link ICustomTabsConnectionService#newSession}. | |
| 44 */ | |
| 45 public static final String EXTRA_CUSTOM_TABS_SESSION_ID = | |
| 46 "android.support.CUSTOM_TABS:session_id"; | |
| 47 | 35 |
| 48 /** | 36 /** |
| 49 * Extra used to keep the caller alive. Its value is an Intent. | 37 * Extra used to keep the caller alive. Its value is an Intent. |
| 50 */ | 38 */ |
| 51 public static final String EXTRA_CUSTOM_TABS_KEEP_ALIVE = | 39 public static final String EXTRA_KEEP_ALIVE = "android.support.customtabs.ex
tra.KEEP_ALIVE"; |
| 52 "android.support.CUSTOM_TABS:keep_alive"; | |
| 53 | |
| 54 /** | |
| 55 * Extra that changes the background color for the omnibox. colorRes is an i
nt that specifies a | |
| 56 * color. | |
| 57 */ | |
| 58 public static final String EXTRA_CUSTOM_TABS_TOOLBAR_COLOR = | |
| 59 "android.support.CUSTOM_TABS:toolbar_color"; | |
| 60 | 40 |
| 61 /** | 41 /** |
| 62 * Extra int that specifies the style of the back button on the toolbar. Def
ault is showing a | 42 * Extra int that specifies the style of the back button on the toolbar. Def
ault is showing a |
| 63 * cross icon. | 43 * cross icon. |
| 64 */ | 44 */ |
| 65 public static final String EXTRA_CUSTOM_TABS_CLOSE_BUTTON_STYLE = | 45 public static final String EXTRA_CLOSE_BUTTON_STYLE = |
| 66 "android.support.CUSTOM_TABS:close_button_style"; | 46 "android.support.customtabs.extra.CLOSE_BUTTON_STYLE"; |
| 67 | 47 |
| 68 /** | 48 /** |
| 69 * Uses 'X'-like cross icon for close button. | 49 * Uses 'X'-like cross icon for close button. |
| 70 */ | 50 */ |
| 71 public static final int CUSTOM_TAB_CLOSE_BUTTON_CROSS = 0; | 51 public static final int CLOSE_BUTTON_CROSS = 0; |
| 72 | 52 |
| 73 /** | 53 /** |
| 74 * Uses '<'-like chevron arrow icon for close button. | 54 * Uses '<'-like chevron arrow icon for close button. |
| 75 */ | 55 */ |
| 76 public static final int CUSTOM_TAB_CLOSE_BUTTON_ARROW = 1; | 56 public static final int CLOSE_BUTTON_ARROW = 1; |
| 77 | 57 |
| 78 /** | 58 /** |
| 79 * Extra int that specifies state for showing the page title. Default is sho
wing only the domain | 59 * Extra int that specifies state for showing the page title. Default is sho
wing only the domain |
| 80 * and no information about the title. | 60 * and no information about the title. |
| 81 */ | 61 */ |
| 82 public static final String EXTRA_CUSTOM_TABS_TITLE_VISIBILITY_STATE = | 62 public static final String EXTRA_TITLE_VISIBILITY_STATE = |
| 83 "android.support.CUSTOM_TABS:title_visibility"; | 63 "android.support.customtabs.extra.TITLE_VISIBILITY"; |
| 84 | 64 |
| 85 /** | 65 /** |
| 86 * Don't show any title. Shows only the domain. | 66 * Don't show any title. Shows only the domain. |
| 87 */ | 67 */ |
| 88 public static final int CUSTOM_TAB_NO_TITLE = 0; | 68 public static final int NO_TITLE = 0; |
| 89 | 69 |
| 90 /** | 70 /** |
| 91 * Shows the page title and the domain. | 71 * Shows the page title and the domain. |
| 92 */ | 72 */ |
| 93 public static final int CUSTOM_TAB_SHOW_PAGE_TITLE = 1; | 73 public static final int SHOW_PAGE_TITLE = 1; |
| 94 | |
| 95 /** | |
| 96 * Bundle used for the action button parameters. | |
| 97 */ | |
| 98 public static final String EXTRA_CUSTOM_TABS_ACTION_BUTTON_BUNDLE = | |
| 99 "android.support.CUSTOM_TABS:action_button_bundle"; | |
| 100 | |
| 101 /** | |
| 102 * Key that specifies the Bitmap to be used as the image source for the acti
on button. | |
| 103 */ | |
| 104 public static final String KEY_CUSTOM_TABS_ICON = "android.support.CUSTOM_TA
BS:icon"; | |
| 105 | |
| 106 /** | |
| 107 * Key that specifies the PendingIntent to launch when the action button or
menu item was | |
| 108 * clicked. Chrome will be calling {@link PendingIntent#send()} on clicks af
ter adding the url | |
| 109 * as data. The client app can call {@link Intent#getDataString()} to get th
e url. | |
| 110 */ | |
| 111 public static final String KEY_CUSTOM_TABS_PENDING_INTENT = | |
| 112 "android.support.CUSTOM_TABS:pending_intent"; | |
| 113 | |
| 114 /** | |
| 115 * Use an {@code ArrayList<Bundle>} for specifying menu related params. Ther
e should be a | |
| 116 * separate Bundle for each custom menu item. | |
| 117 */ | |
| 118 public static final String EXTRA_CUSTOM_TABS_MENU_ITEMS = | |
| 119 "android.support.CUSTOM_TABS:menu_items"; | |
| 120 | |
| 121 /** | |
| 122 * Key for the title of a menu item. | |
| 123 */ | |
| 124 public static final String KEY_CUSTOM_TABS_MENU_TITLE = | |
| 125 "android.support.CUSTOM_TABS:menu_title"; | |
| 126 | |
| 127 /** | |
| 128 * Bundle constructed out of ActivityOptions that Chrome will be running whe
n it finishes | |
| 129 * {@link CustomTabActivity}. A similar ActivityOptions for starting Chrome
should be | |
| 130 * constructed and given to the startActivity() call that launches Chrome. | |
| 131 */ | |
| 132 public static final String EXTRA_CUSTOM_TABS_EXIT_ANIMATION_BUNDLE = | |
| 133 "android.support.CUSTOM_TABS:exit_animation_bundle"; | |
| 134 | |
| 135 /** | |
| 136 * An invalid session ID, used when none is provided in the intent. | |
| 137 */ | |
| 138 public static final long INVALID_SESSION_ID = -1; | |
| 139 | 74 |
| 140 private static final String BUNDLE_PACKAGE_NAME = "android:packageName"; | 75 private static final String BUNDLE_PACKAGE_NAME = "android:packageName"; |
| 141 private static final String BUNDLE_ENTER_ANIMATION_RESOURCE = "android:animE
nterRes"; | 76 private static final String BUNDLE_ENTER_ANIMATION_RESOURCE = "android:animE
nterRes"; |
| 142 private static final String BUNDLE_EXIT_ANIMATION_RESOURCE = "android:animEx
itRes"; | 77 private static final String BUNDLE_EXIT_ANIMATION_RESOURCE = "android:animEx
itRes"; |
| 143 private final long mSessionId; | 78 private final IBinder mSession; |
| 144 private final Intent mKeepAliveServiceIntent; | 79 private final Intent mKeepAliveServiceIntent; |
| 145 private final int mTitleVisibilityState; | 80 private final int mTitleVisibilityState; |
| 146 private final int mCloseButtonResId; | 81 private final int mCloseButtonResId; |
| 147 private int mToolbarColor; | 82 private int mToolbarColor; |
| 148 private Bitmap mIcon; | 83 private Bitmap mIcon; |
| 149 private PendingIntent mActionButtonPendingIntent; | 84 private PendingIntent mActionButtonPendingIntent; |
| 150 private List<Pair<String, PendingIntent>> mMenuEntries = new ArrayList<>(); | 85 private List<Pair<String, PendingIntent>> mMenuEntries = new ArrayList<>(); |
| 151 private Bundle mAnimationBundle; | 86 private Bundle mAnimationBundle; |
| 152 // OnFinished listener for PendingIntents. Used for testing only. | 87 // OnFinished listener for PendingIntents. Used for testing only. |
| 153 private PendingIntent.OnFinished mOnFinished; | 88 private PendingIntent.OnFinished mOnFinished; |
| 154 | 89 |
| 155 /** | 90 /** |
| 156 * Constructs a {@link CustomTabIntentDataProvider}. | 91 * Constructs a {@link CustomTabIntentDataProvider}. |
| 157 */ | 92 */ |
| 158 public CustomTabIntentDataProvider(Intent intent, Context context) { | 93 public CustomTabIntentDataProvider(Intent intent, Context context) { |
| 159 if (intent == null) assert false; | 94 if (intent == null) assert false; |
| 160 | 95 |
| 161 mSessionId = IntentUtils.safeGetLongExtra( | 96 mSession = IntentUtils.safeGetBinderExtra(intent, CustomTabsIntent.EXTRA
_SESSION); |
| 162 intent, EXTRA_CUSTOM_TABS_SESSION_ID, INVALID_SESSION_ID); | |
| 163 retrieveToolbarColor(intent, context); | 97 retrieveToolbarColor(intent, context); |
| 98 mKeepAliveServiceIntent = IntentUtils.safeGetParcelableExtra(intent, EXT
RA_KEEP_ALIVE); |
| 164 | 99 |
| 165 mKeepAliveServiceIntent = IntentUtils.safeGetParcelableExtra( | 100 Bundle actionButtonBundle = |
| 166 intent, EXTRA_CUSTOM_TABS_KEEP_ALIVE); | 101 IntentUtils.safeGetBundleExtra(intent, CustomTabsIntent.EXTRA_AC
TION_BUTTON_BUNDLE); |
| 167 | |
| 168 Bundle actionButtonBundle = IntentUtils.safeGetBundleExtra( | |
| 169 intent, EXTRA_CUSTOM_TABS_ACTION_BUTTON_BUNDLE); | |
| 170 if (actionButtonBundle != null) { | 102 if (actionButtonBundle != null) { |
| 171 mIcon = IntentUtils.safeGetParcelable(actionButtonBundle, KEY_CUSTOM
_TABS_ICON); | 103 mIcon = IntentUtils.safeGetParcelable(actionButtonBundle, CustomTabs
Intent.KEY_ICON); |
| 172 if (!checkBitmapSizeWithinBounds(context, mIcon)) { | 104 if (mIcon != null && !checkBitmapSizeWithinBounds(context, mIcon)) { |
| 173 mIcon.recycle(); | 105 mIcon.recycle(); |
| 174 mIcon = null; | 106 mIcon = null; |
| 175 } else { | 107 } else if (mIcon != null) { |
| 176 mActionButtonPendingIntent = IntentUtils.safeGetParcelable( | 108 mActionButtonPendingIntent = IntentUtils.safeGetParcelable( |
| 177 actionButtonBundle, KEY_CUSTOM_TABS_PENDING_INTENT); | 109 actionButtonBundle, CustomTabsIntent.KEY_PENDING_INTENT)
; |
| 178 } | 110 } |
| 179 } | 111 } |
| 180 | 112 |
| 181 List<Bundle> menuItems = IntentUtils.getParcelableArrayListExtra( | 113 List<Bundle> menuItems = |
| 182 intent, EXTRA_CUSTOM_TABS_MENU_ITEMS); | 114 IntentUtils.getParcelableArrayListExtra(intent, CustomTabsIntent
.EXTRA_MENU_ITEMS); |
| 183 if (menuItems != null) { | 115 if (menuItems != null) { |
| 184 for (Bundle bundle : menuItems) { | 116 for (Bundle bundle : menuItems) { |
| 185 String title = IntentUtils.safeGetString(bundle, KEY_CUSTOM_TABS
_MENU_TITLE); | 117 String title = |
| 186 PendingIntent pendingIntent = IntentUtils.safeGetParcelable( | 118 IntentUtils.safeGetString(bundle, CustomTabsIntent.KEY_M
ENU_ITEM_TITLE); |
| 187 bundle, KEY_CUSTOM_TABS_PENDING_INTENT); | 119 PendingIntent pendingIntent = |
| 120 IntentUtils.safeGetParcelable(bundle, CustomTabsIntent.K
EY_PENDING_INTENT); |
| 188 if (TextUtils.isEmpty(title) || pendingIntent == null) continue; | 121 if (TextUtils.isEmpty(title) || pendingIntent == null) continue; |
| 189 mMenuEntries.add(new Pair<String, PendingIntent>(title, pendingI
ntent)); | 122 mMenuEntries.add(new Pair<String, PendingIntent>(title, pendingI
ntent)); |
| 190 } | 123 } |
| 191 } | 124 } |
| 192 | 125 |
| 193 mAnimationBundle = IntentUtils.safeGetBundleExtra( | 126 mAnimationBundle = IntentUtils.safeGetBundleExtra( |
| 194 intent, EXTRA_CUSTOM_TABS_EXIT_ANIMATION_BUNDLE); | 127 intent, CustomTabsIntent.EXTRA_EXIT_ANIMATION_BUNDLE); |
| 195 | 128 |
| 196 int closeButtonStyle = IntentUtils.safeGetIntExtra(intent, | 129 int closeButtonStyle = |
| 197 EXTRA_CUSTOM_TABS_CLOSE_BUTTON_STYLE, CUSTOM_TAB_CLOSE_BUTTON_CR
OSS); | 130 IntentUtils.safeGetIntExtra(intent, EXTRA_CLOSE_BUTTON_STYLE, CL
OSE_BUTTON_CROSS); |
| 198 switch(closeButtonStyle) { | 131 switch(closeButtonStyle) { |
| 199 case CustomTabIntentDataProvider.CUSTOM_TAB_CLOSE_BUTTON_ARROW: | 132 case CustomTabIntentDataProvider.CLOSE_BUTTON_ARROW: |
| 200 mCloseButtonResId = R.drawable.btn_chevron_left; | 133 mCloseButtonResId = R.drawable.btn_chevron_left; |
| 201 break; | 134 break; |
| 202 case CustomTabIntentDataProvider.CUSTOM_TAB_CLOSE_BUTTON_CROSS: | 135 case CustomTabIntentDataProvider.CLOSE_BUTTON_CROSS: |
| 203 default: | 136 default: |
| 204 mCloseButtonResId = R.drawable.btn_close; | 137 mCloseButtonResId = R.drawable.btn_close; |
| 205 } | 138 } |
| 206 | 139 |
| 207 mTitleVisibilityState = IntentUtils.safeGetIntExtra( | 140 mTitleVisibilityState = |
| 208 intent, EXTRA_CUSTOM_TABS_TITLE_VISIBILITY_STATE, CUSTOM_TAB_NO_
TITLE); | 141 IntentUtils.safeGetIntExtra(intent, EXTRA_TITLE_VISIBILITY_STATE
, NO_TITLE); |
| 209 } | 142 } |
| 210 | 143 |
| 211 /** | 144 /** |
| 212 * Processes the color passed from the client app and updates {@link #mToolb
arColor}. | 145 * Processes the color passed from the client app and updates {@link #mToolb
arColor}. |
| 213 */ | 146 */ |
| 214 private void retrieveToolbarColor(Intent intent, Context context) { | 147 private void retrieveToolbarColor(Intent intent, Context context) { |
| 215 int color = IntentUtils.safeGetIntExtra(intent, EXTRA_CUSTOM_TABS_TOOLBA
R_COLOR, | 148 int color = IntentUtils.safeGetIntExtra(intent, CustomTabsIntent.EXTRA_T
OOLBAR_COLOR, |
| 216 context.getResources().getColor(R.color.default_primary_color)); | 149 context.getResources().getColor(R.color.default_primary_color)); |
| 217 int defaultColor = context.getResources().getColor(R.color.default_prima
ry_color); | 150 int defaultColor = context.getResources().getColor(R.color.default_prima
ry_color); |
| 218 | 151 |
| 219 if (color == Color.TRANSPARENT) color = defaultColor; | 152 if (color == Color.TRANSPARENT) color = defaultColor; |
| 220 | 153 |
| 221 // Ignore any transparency value. | 154 // Ignore any transparency value. |
| 222 color |= 0xFF000000; | 155 color |= 0xFF000000; |
| 223 | 156 |
| 224 mToolbarColor = color; | 157 mToolbarColor = color; |
| 225 } | 158 } |
| 226 | 159 |
| 227 /** | 160 /** |
| 228 * @return The session ID specified in the intent. Will be | 161 * @return The session specified in the intent, or null. |
| 229 * INVALID_SESSION_ID if it is not set in the intent. | |
| 230 */ | 162 */ |
| 231 public long getSessionId() { | 163 public IBinder getSession() { |
| 232 return mSessionId; | 164 return mSession; |
| 233 } | 165 } |
| 234 | 166 |
| 235 /** | 167 /** |
| 236 * @return The keep alive service intent specified in the intent, or null. | 168 * @return The keep alive service intent specified in the intent, or null. |
| 237 */ | 169 */ |
| 238 public Intent getKeepAliveServiceIntent() { | 170 public Intent getKeepAliveServiceIntent() { |
| 239 return mKeepAliveServiceIntent; | 171 return mKeepAliveServiceIntent; |
| 240 } | 172 } |
| 241 | 173 |
| 242 /** | 174 /** |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 | 306 |
| 375 /** | 307 /** |
| 376 * Set the callback object for {@link PendingIntent}s that are sent in this
class. For testing | 308 * Set the callback object for {@link PendingIntent}s that are sent in this
class. For testing |
| 377 * purpose only. | 309 * purpose only. |
| 378 */ | 310 */ |
| 379 @VisibleForTesting | 311 @VisibleForTesting |
| 380 void setPendingIntentOnFinishedForTesting(PendingIntent.OnFinished onFinishe
d) { | 312 void setPendingIntentOnFinishedForTesting(PendingIntent.OnFinished onFinishe
d) { |
| 381 mOnFinished = onFinished; | 313 mOnFinished = onFinished; |
| 382 } | 314 } |
| 383 } | 315 } |
| OLD | NEW |