1/* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.support.customtabs; 18 19import android.app.Activity; 20import android.app.ActivityOptions; 21import android.app.PendingIntent; 22import android.content.Context; 23import android.content.Intent; 24import android.graphics.Bitmap; 25import android.graphics.Color; 26import android.net.Uri; 27import android.os.Bundle; 28import android.support.annotation.AnimRes; 29import android.support.annotation.ColorInt; 30import android.support.annotation.NonNull; 31import android.support.annotation.Nullable; 32import android.support.v4.app.BundleCompat; 33 34import java.util.ArrayList; 35 36/** 37 * Class holding the {@link Intent} and start bundle for a Custom Tabs Activity. 38 * 39 * <p> 40 * <strong>Note:</strong> The constants below are public for the browser implementation's benefit. 41 * You are strongly encouraged to use {@link CustomTabsIntent.Builder}.</p> 42 */ 43public final class CustomTabsIntent { 44 45 /** 46 * Extra used to match the session. This has to be included in the intent to open in 47 * a custom tab. This is the same IBinder that gets passed to ICustomTabsService#newSession. 48 * Null if there is no need to match any service side sessions with the intent. 49 */ 50 public static final String EXTRA_SESSION = "android.support.customtabs.extra.SESSION"; 51 52 /** 53 * Extra that changes the background color for the toolbar. colorRes is an int that specifies a 54 * {@link Color}, not a resource id. 55 */ 56 public static final String EXTRA_TOOLBAR_COLOR = 57 "android.support.customtabs.extra.TOOLBAR_COLOR"; 58 59 /** 60 * Extra bitmap that specifies the icon of the back button on the toolbar. If the client chooses 61 * not to customize it, a default close button will be used. 62 */ 63 public static final String EXTRA_CLOSE_BUTTON_ICON = 64 "android.support.customtabs.extra.CLOSE_BUTTON_ICON"; 65 66 /** 67 * Extra (int) that specifies state for showing the page title. Default is {@link #NO_TITLE}. 68 */ 69 public static final String EXTRA_TITLE_VISIBILITY_STATE = 70 "android.support.customtabs.extra.TITLE_VISIBILITY"; 71 72 /** 73 * Don't show any title. Shows only the domain. 74 */ 75 public static final int NO_TITLE = 0; 76 77 /** 78 * Shows the page title and the domain. 79 */ 80 public static final int SHOW_PAGE_TITLE = 1; 81 82 /** 83 * Bundle used for adding a custom action button to the custom tab toolbar. The client should 84 * provide a description, an icon {@link Bitmap} and a {@link PendingIntent} for the button. 85 * All three keys must be present. 86 */ 87 public static final String EXTRA_ACTION_BUTTON_BUNDLE = 88 "android.support.customtabs.extra.ACTION_BUTTON_BUNDLE"; 89 90 /** 91 * Key that specifies the {@link Bitmap} to be used as the image source for the action button. 92 * The icon should't be more than 24dp in height (No padding needed. The button itself will be 93 * 48dp in height) and have a width/height ratio of less than 2. 94 */ 95 public static final String KEY_ICON = "android.support.customtabs.customaction.ICON"; 96 97 /** 98 * Key that specifies the content description for the custom action button. 99 */ 100 public static final String KEY_DESCRIPTION = 101 "android.support.customtabs.customaction.DESCRIPTION"; 102 103 /** 104 * Key that specifies the PendingIntent to launch when the action button or menu item was 105 * clicked. The custom tab will be calling {@link PendingIntent#send()} on clicks after adding 106 * the url as data. The client app can call {@link Intent#getDataString()} to get the url. 107 */ 108 public static final String KEY_PENDING_INTENT = 109 "android.support.customtabs.customaction.PENDING_INTENT"; 110 111 /** 112 * Use an {@code ArrayList<Bundle>} for specifying menu related params. There should be a 113 * separate {@link Bundle} for each custom menu item. 114 */ 115 public static final String EXTRA_MENU_ITEMS = "android.support.customtabs.extra.MENU_ITEMS"; 116 117 /** 118 * Key for specifying the title of a menu item. 119 */ 120 public static final String KEY_MENU_ITEM_TITLE = 121 "android.support.customtabs.customaction.MENU_ITEM_TITLE"; 122 123 /** 124 * Bundle constructed out of {@link ActivityOptions} that will be running when the 125 * {@link Activity} that holds the custom tab gets finished. A similar ActivityOptions 126 * for creation should be constructed and given to the startActivity() call that 127 * launches the custom tab. 128 */ 129 public static final String EXTRA_EXIT_ANIMATION_BUNDLE = 130 "android.support.customtabs.extra.EXIT_ANIMATION_BUNDLE"; 131 132 /** 133 * An {@link Intent} used to start the Custom Tabs Activity. 134 */ 135 @NonNull public final Intent intent; 136 137 /** 138 * A {@link Bundle} containing the start animation for the Custom Tabs Activity. 139 */ 140 @Nullable public final Bundle startAnimationBundle; 141 142 /** 143 * Convenience method to launch a Custom Tabs Activity. 144 * @param context The source Activity. 145 * @param url The URL to load in the Custom Tab. 146 */ 147 public void launchUrl(Activity context, Uri url) { 148 intent.setData(url); 149 if (startAnimationBundle != null){ 150 context.startActivity(intent, startAnimationBundle); 151 } else { 152 context.startActivity(intent); 153 } 154 } 155 156 private CustomTabsIntent(Intent intent, Bundle startAnimationBundle) { 157 this.intent = intent; 158 this.startAnimationBundle = startAnimationBundle; 159 } 160 161 /** 162 * Builder class for {@link CustomTabsIntent} objects. 163 */ 164 public static final class Builder { 165 private final Intent mIntent = new Intent(Intent.ACTION_VIEW); 166 private ArrayList<Bundle> mMenuItems = null; 167 private Bundle mStartAnimationBundle = null; 168 169 /** 170 * Creates a {@link CustomTabsIntent.Builder} object associated with no 171 * {@link CustomTabsSession}. 172 */ 173 public Builder() { 174 this(null); 175 } 176 177 /** 178 * Creates a {@link CustomTabsIntent.Builder} object associated with a given 179 * {@link CustomTabsSession}. 180 * 181 * Guarantees that the {@link Intent} will be sent to the same component as the one the 182 * session is associated with. 183 * 184 * @param session The session to associate this Builder with. 185 */ 186 public Builder(@Nullable CustomTabsSession session) { 187 if (session != null) mIntent.setPackage(session.getComponentName().getPackageName()); 188 Bundle bundle = new Bundle(); 189 BundleCompat.putBinder( 190 bundle, EXTRA_SESSION, session == null ? null : session.getBinder()); 191 mIntent.putExtras(bundle); 192 } 193 194 /** 195 * Sets the toolbar color. 196 * 197 * @param color {@link Color} 198 */ 199 public Builder setToolbarColor(@ColorInt int color) { 200 mIntent.putExtra(EXTRA_TOOLBAR_COLOR, color); 201 return this; 202 } 203 204 /** 205 * Sets the Close button icon for the custom tab. 206 * 207 * @param icon The icon {@link Bitmap} 208 */ 209 public Builder setCloseButtonIcon(@NonNull Bitmap icon) { 210 mIntent.putExtra(EXTRA_CLOSE_BUTTON_ICON, icon); 211 return this; 212 } 213 214 /** 215 * Sets whether the title should be shown in the custom tab. 216 * 217 * @param showTitle Whether the title should be shown. 218 */ 219 public Builder setShowTitle(boolean showTitle) { 220 mIntent.putExtra(EXTRA_TITLE_VISIBILITY_STATE, 221 showTitle ? SHOW_PAGE_TITLE : NO_TITLE); 222 return this; 223 } 224 225 /** 226 * Adds a menu item. 227 * 228 * @param label Menu label. 229 * @param pendingIntent Pending intent delivered when the menu item is clicked. 230 */ 231 public Builder addMenuItem(@NonNull String label, @NonNull PendingIntent pendingIntent) { 232 if (mMenuItems == null) mMenuItems = new ArrayList<>(); 233 Bundle bundle = new Bundle(); 234 bundle.putString(KEY_MENU_ITEM_TITLE, label); 235 bundle.putParcelable(KEY_PENDING_INTENT, pendingIntent); 236 mMenuItems.add(bundle); 237 return this; 238 } 239 240 /** 241 * Set the action button. 242 * 243 * @param icon The icon. 244 * @param description The description for the button. To be used for accessibility. 245 * @param pendingIntent pending intent delivered when the button is clicked. 246 */ 247 public Builder setActionButton(@NonNull Bitmap icon, 248 @NonNull String description, @NonNull PendingIntent pendingIntent) { 249 Bundle bundle = new Bundle(); 250 bundle.putParcelable(KEY_ICON, icon); 251 bundle.putString(KEY_DESCRIPTION, description); 252 bundle.putParcelable(KEY_PENDING_INTENT, pendingIntent); 253 mIntent.putExtra(EXTRA_ACTION_BUTTON_BUNDLE, bundle); 254 return this; 255 } 256 257 /** 258 * Sets the start animations, 259 * 260 * @param context Application context. 261 * @param enterResId Resource ID of the "enter" animation for the browser. 262 * @param exitResId Resource ID of the "exit" animation for the application. 263 */ 264 public Builder setStartAnimations( 265 @NonNull Context context, @AnimRes int enterResId, @AnimRes int exitResId) { 266 mStartAnimationBundle = 267 ActivityOptions.makeCustomAnimation(context, enterResId, exitResId).toBundle(); 268 return this; 269 } 270 271 /** 272 * Sets the exit animations, 273 * 274 * @param context Application context. 275 * @param enterResId Resource ID of the "enter" animation for the application. 276 * @param exitResId Resource ID of the "exit" animation for the browser. 277 */ 278 public Builder setExitAnimations( 279 @NonNull Context context, @AnimRes int enterResId, @AnimRes int exitResId) { 280 Bundle bundle = 281 ActivityOptions.makeCustomAnimation(context, enterResId, exitResId).toBundle(); 282 mIntent.putExtra(EXTRA_EXIT_ANIMATION_BUNDLE, bundle); 283 return this; 284 } 285 286 /** 287 * Combines all the options that have been set and returns a new {@link CustomTabsIntent} 288 * object. 289 */ 290 public CustomTabsIntent build() { 291 if (mMenuItems != null) { 292 mIntent.putParcelableArrayListExtra(CustomTabsIntent.EXTRA_MENU_ITEMS, mMenuItems); 293 } 294 return new CustomTabsIntent(mIntent, mStartAnimationBundle); 295 } 296 } 297} 298