CustomTabsIntent.java revision 9440f0b000fc2740382eb4ae5f1afec58c245c2c
108889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal/*
208889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal * Copyright (C) 2015 The Android Open Source Project
308889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal *
408889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal * Licensed under the Apache License, Version 2.0 (the "License");
508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal * you may not use this file except in compliance with the License.
608889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal * You may obtain a copy of the License at
708889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal *
808889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal *      http://www.apache.org/licenses/LICENSE-2.0
908889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal *
1008889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal * Unless required by applicable law or agreed to in writing, software
1108889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal * distributed under the License is distributed on an "AS IS" BASIS,
1208889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1308889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal * See the License for the specific language governing permissions and
1408889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal * limitations under the License.
1508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal */
1608889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
1708889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalpackage android.support.customtabs;
1808889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
1908889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalimport android.app.Activity;
2008889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalimport android.app.ActivityOptions;
2108889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalimport android.app.PendingIntent;
2297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lizeimport android.content.Context;
2308889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalimport android.content.Intent;
2408889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalimport android.graphics.Bitmap;
2508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalimport android.graphics.Color;
2608889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalimport android.net.Uri;
2708889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalimport android.os.Build;
2808889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalimport android.os.Bundle;
2908889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalimport android.os.IBinder;
3097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lizeimport android.support.annotation.AnimRes;
3197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lizeimport android.support.annotation.NonNull;
3297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lizeimport android.support.annotation.ColorInt;
3397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lizeimport android.support.annotation.Nullable;
3408889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
3508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalimport java.lang.reflect.InvocationTargetException;
3608889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysalimport java.lang.reflect.Method;
3797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lizeimport java.util.ArrayList;
3808889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
3908889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal/**
4097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize * Class holding the {@link Intent} and start bundle for a Custom Tabs Activity.
4197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize *
4297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize * <p>
4397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize * <strong>Note:</strong> The constants below are public for the browser implementation's benefit.
4497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize * You are strongly encouraged to use {@link CustomTabsIntent.Builder}.</p>
4508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal */
4697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lizepublic final class CustomTabsIntent {
4708889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
4808889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    /**
4908889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * Extra used to match the session. This has to be included in the intent to open in
5008889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * a custom tab. This is the same IBinder that gets passed to ICustomTabsService#newSession.
5108889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * Null if there is no need to match any service side sessions with the intent.
5208889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     */
5308889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    public static final String EXTRA_SESSION = "android.support.customtabs.extra.SESSION";
5408889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
5508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    /**
5608889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * Extra that changes the background color for the toolbar. colorRes is an int that specifies a
5708889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * {@link Color}, not a resource id.
5808889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     */
5908889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    public static final String EXTRA_TOOLBAR_COLOR =
6008889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal            "android.support.customtabs.extra.TOOLBAR_COLOR";
6108889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
6208889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    /**
639440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal     * Boolean extra that enables the url bar to hide as the user scrolls down the page
649440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal     */
659440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal    public static final String EXTRA_ENABLE_URLBAR_HIDING =
669440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal            "android.support.customtabs.extra.ENABLE_URLBAR_HIDING";
679440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal
689440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal    /**
6997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     * Extra bitmap that specifies the icon of the back button on the toolbar. If the client chooses
7097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     * not to customize it, a default close button will be used.
7197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     */
7297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    public static final String EXTRA_CLOSE_BUTTON_ICON =
7397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            "android.support.customtabs.extra.CLOSE_BUTTON_ICON";
7497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
7597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    /**
7697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     * Extra (int) that specifies state for showing the page title. Default is {@link #NO_TITLE}.
7797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     */
7897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    public static final String EXTRA_TITLE_VISIBILITY_STATE =
7997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            "android.support.customtabs.extra.TITLE_VISIBILITY";
8097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
8197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    /**
8297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     * Don't show any title. Shows only the domain.
8397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     */
8497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    public static final int NO_TITLE = 0;
8597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
8697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    /**
8797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     * Shows the page title and the domain.
8897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     */
8997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    public static final int SHOW_PAGE_TITLE = 1;
9097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
9197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    /**
928a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal     * Bundle used for adding a custom action button to the custom tab toolbar. The client should
938a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal     * provide a description, an icon {@link Bitmap} and a {@link PendingIntent} for the button.
948a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal     * All three keys must be present.
9508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     */
9608889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    public static final String EXTRA_ACTION_BUTTON_BUNDLE =
9708889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal            "android.support.customtabs.extra.ACTION_BUTTON_BUNDLE";
9808889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
9908889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    /**
10008889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * Key that specifies the {@link Bitmap} to be used as the image source for the action button.
1018a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal     *  The icon should't be more than 24dp in height (No padding needed. The button itself will be
1028a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal     *  48dp in height) and have a width/height ratio of less than 2.
10308889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     */
10408889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    public static final String KEY_ICON = "android.support.customtabs.customaction.ICON";
10508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
10608889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    /**
1078a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal     * Key that specifies the content description for the custom action button.
1088a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal     */
1098a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal    public static final String KEY_DESCRIPTION =
1108a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal            "android.support.customtabs.customaction.DESCRIPTION";
1118a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal
1128a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal    /**
11308889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * Key that specifies the PendingIntent to launch when the action button or menu item was
11408889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * clicked. The custom tab will be calling {@link PendingIntent#send()} on clicks after adding
11508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * the url as data. The client app can call {@link Intent#getDataString()} to get the url.
11608889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     */
11708889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    public static final String KEY_PENDING_INTENT =
11808889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal            "android.support.customtabs.customaction.PENDING_INTENT";
11908889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
12008889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    /**
1219440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal     * Extra boolean that specifies whether the custom action button should be tinted. Default is
1229440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal     * false and the action button will not be tinted.
1239440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal     */
1249440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal    public static final String EXTRA_TINT_ACTION_BUTTON =
1259440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal            "android.support.customtabs.extra.TINT_ACTION_BUTTON";
1269440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal
1279440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal    /**
12808889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * Use an {@code ArrayList<Bundle>} for specifying menu related params. There should be a
12908889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * separate {@link Bundle} for each custom menu item.
13008889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     */
13108889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    public static final String EXTRA_MENU_ITEMS = "android.support.customtabs.extra.MENU_ITEMS";
13208889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
13308889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    /**
13408889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * Key for specifying the title of a menu item.
13508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     */
13608889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    public static final String KEY_MENU_ITEM_TITLE =
13708889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal            "android.support.customtabs.customaction.MENU_ITEM_TITLE";
13808889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
13908889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    /**
14008889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * Bundle constructed out of {@link ActivityOptions} that will be running when the
14108889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * {@link Activity} that holds the custom tab gets finished. A similar ActivityOptions
14208889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * for creation should be constructed and given to the startActivity() call that
14308889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     * launches the custom tab.
14408889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     */
14508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    public static final String EXTRA_EXIT_ANIMATION_BUNDLE =
14608889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal            "android.support.customtabs.extra.EXIT_ANIMATION_BUNDLE";
14708889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
14808889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    /**
14997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     * An {@link Intent} used to start the Custom Tabs Activity.
15097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     */
15197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    @NonNull public final Intent intent;
15297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
15397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    /**
15497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     * A {@link Bundle} containing the start animation for the Custom Tabs Activity.
15508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal     */
15697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    @Nullable public final Bundle startAnimationBundle;
15797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
15897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    /**
15997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     * Convenience method to launch a Custom Tabs Activity.
16097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     * @param context The source Activity.
16197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     * @param url The URL to load in the Custom Tab.
16297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     */
16397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    public void launchUrl(Activity context, Uri url) {
16497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        intent.setData(url);
16597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        if (startAnimationBundle != null){
16697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            context.startActivity(intent, startAnimationBundle);
16797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        } else {
16897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            context.startActivity(intent);
16997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        }
17097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    }
17197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
17297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    private CustomTabsIntent(Intent intent, Bundle startAnimationBundle) {
17397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        this.intent = intent;
17497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        this.startAnimationBundle = startAnimationBundle;
17508889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    }
17608889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal
17708889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    /**
17897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     * Builder class for {@link CustomTabsIntent} objects.
17997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize     */
18097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize    public static final class Builder {
18197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        private final Intent mIntent = new Intent(Intent.ACTION_VIEW);
18297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        private ArrayList<Bundle> mMenuItems = null;
18397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        private Bundle mStartAnimationBundle = null;
18497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
18597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        /**
18697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * Creates a {@link CustomTabsIntent.Builder} object associated with no
18797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * {@link CustomTabsSession}.
18897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         */
18997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        public Builder() {
19097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            this(null);
19197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        }
19297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
19397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        /**
19497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * Creates a {@link CustomTabsIntent.Builder} object associated with a given
19597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * {@link CustomTabsSession}.
19697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         *
19797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * Guarantees that the {@link Intent} will be sent to the same component as the one the
19897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * session is associated with.
19997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         *
20097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param session The session to associate this Builder with.
20197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         */
20297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        public Builder(@Nullable CustomTabsSession session) {
20397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            if (session != null) mIntent.setPackage(session.getComponentName().getPackageName());
20497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            Bundle bundle = new Bundle();
20597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            safePutBinder(bundle, EXTRA_SESSION, session == null ? null : session.getBinder());
20697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            mIntent.putExtras(bundle);
20797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        }
20897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
20997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        /**
21097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * Sets the toolbar color.
21197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         *
21297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param color {@link Color}
21397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         */
21497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        public Builder setToolbarColor(@ColorInt int color) {
21597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            mIntent.putExtra(EXTRA_TOOLBAR_COLOR, color);
21697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            return this;
21797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        }
21897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
21997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        /**
2209440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal         * Enables the url bar to hide as the user scrolls down on the page.
2219440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal         */
2229440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal        public Builder enableUrlBarHiding() {
2239440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal            mIntent.putExtra(EXTRA_ENABLE_URLBAR_HIDING, true);
2249440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal            return this;
2259440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal        }
2269440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal
2279440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal        /**
22897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * Sets the Close button icon for the custom tab.
22997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         *
23097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param icon The icon {@link Bitmap}
23197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         */
23297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        public Builder setCloseButtonIcon(@NonNull Bitmap icon) {
23397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            mIntent.putExtra(EXTRA_CLOSE_BUTTON_ICON, icon);
23497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            return this;
23597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        }
23697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
23797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        /**
23897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * Sets whether the title should be shown in the custom tab.
23997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         *
24097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param showTitle Whether the title should be shown.
24197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         */
24297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        public Builder setShowTitle(boolean showTitle) {
24397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            mIntent.putExtra(EXTRA_TITLE_VISIBILITY_STATE,
24497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                    showTitle ? SHOW_PAGE_TITLE : NO_TITLE);
24597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            return this;
24697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        }
24797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
24897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        /**
24997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * Adds a menu item.
25097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         *
25197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param label Menu label.
25297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param pendingIntent Pending intent delivered when the menu item is clicked.
25397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         */
25497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        public Builder addMenuItem(@NonNull String label, @NonNull PendingIntent pendingIntent) {
25597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            if (mMenuItems == null) mMenuItems = new ArrayList<>();
25697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            Bundle bundle = new Bundle();
25797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            bundle.putString(KEY_MENU_ITEM_TITLE, label);
25897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            bundle.putParcelable(KEY_PENDING_INTENT, pendingIntent);
25997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            mMenuItems.add(bundle);
26097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            return this;
26197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        }
26297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
26397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        /**
26497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * Set the action button.
26597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         *
26697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param icon The icon.
2678a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal         * @param description The description for the button. To be used for accessibility.
26897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param pendingIntent pending intent delivered when the button is clicked.
2699440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal         * @param shouldTint Whether the action button should be tinted.
27097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         */
2719440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal        public Builder setActionButton(@NonNull Bitmap icon, @NonNull String description,
2729440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal                @NonNull PendingIntent pendingIntent, boolean shouldTint) {
27397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            Bundle bundle = new Bundle();
27497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            bundle.putParcelable(KEY_ICON, icon);
2758a1ccd14081000d6501622de72a16da67c33030cYusuf Ozuysal            bundle.putString(KEY_DESCRIPTION, description);
27697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            bundle.putParcelable(KEY_PENDING_INTENT, pendingIntent);
27797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            mIntent.putExtra(EXTRA_ACTION_BUTTON_BUNDLE, bundle);
2789440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal            mIntent.putExtra(EXTRA_TINT_ACTION_BUTTON, shouldTint);
27997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            return this;
28097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        }
28197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
28297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        /**
2839440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal         * See {@link CustomTabsIntent.Builder#setActionButton(
2849440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal         * Bitmap, String, PendingIntent, boolean)}
2859440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal         */
2869440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal        public Builder setActionButton(@NonNull Bitmap icon, @NonNull String description,
2879440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal                @NonNull PendingIntent pendingIntent) {
2889440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal            return setActionButton(icon, description, pendingIntent, false);
2899440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal        }
2909440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal
2919440f0b000fc2740382eb4ae5f1afec58c245c2cYusuf Ozuysal        /**
29297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * Sets the start animations,
29397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         *
29497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param context Application context.
29597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param enterResId Resource ID of the "enter" animation for the browser.
29697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param exitResId Resource ID of the "exit" animation for the application.
29797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         */
29897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        public Builder setStartAnimations(
29997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                @NonNull Context context, @AnimRes int enterResId, @AnimRes int exitResId) {
30097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            mStartAnimationBundle =
30197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                    ActivityOptions.makeCustomAnimation(context, enterResId, exitResId).toBundle();
30297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            return this;
30397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        }
30497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
30597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        /**
30697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * Sets the exit animations,
30797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         *
30897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param context Application context.
30997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param enterResId Resource ID of the "enter" animation for the application.
31097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param exitResId Resource ID of the "exit" animation for the browser.
31197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         */
31297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        public Builder setExitAnimations(
31397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                @NonNull Context context, @AnimRes int enterResId, @AnimRes int exitResId) {
31497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            Bundle bundle =
31597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                    ActivityOptions.makeCustomAnimation(context, enterResId, exitResId).toBundle();
31697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            mIntent.putExtra(EXTRA_EXIT_ANIMATION_BUNDLE, bundle);
31797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            return this;
31897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        }
31997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
32097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        /**
32197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * Combines all the options that have been set and returns a new {@link CustomTabsIntent}
32297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * object.
32397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         */
32497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        public CustomTabsIntent build() {
32597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            if (mMenuItems != null) {
32697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                mIntent.putParcelableArrayListExtra(CustomTabsIntent.EXTRA_MENU_ITEMS, mMenuItems);
32797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            }
32897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            return new CustomTabsIntent(mIntent, mStartAnimationBundle);
32997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        }
33097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize
33197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        /**
33297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * A convenience method to handle putting an {@link IBinder} inside a {@link Bundle} for all
33397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * Android version.
33497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param bundle The bundle to insert the {@link IBinder}.
33597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param key    The key to use while putting the {@link IBinder}.
33697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @param binder The {@link IBinder} to put.
33797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         * @return       Whether the operation was successful.
33897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize         */
33997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize        private boolean safePutBinder(Bundle bundle, String key, IBinder binder) {
34097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            try {
34197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                // {@link Bundle#putBinder} exists since JB MR2, but we have
34297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                // {@link Bundle#putIBinder} which is the same method since the dawn of time. Use
34397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                // reflection when necessary to call it.
34497ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
34597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                    bundle.putBinder(key, binder);
34697ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                } else {
34797ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                    Method putBinderMethod =
34897ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                            Bundle.class.getMethod("putIBinder", String.class, IBinder.class);
34997ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                    putBinderMethod.invoke(bundle, key, binder);
35097ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                }
35197ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            } catch (InvocationTargetException | IllegalAccessException
35297ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                    | IllegalArgumentException | NoSuchMethodException e) {
35397ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize                return false;
35408889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal            }
35597ee4f3f353309991efd3ceca369548b485e9a5fBenoit Lize            return true;
35608889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal        }
35708889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal    }
35808889acbc842c73b64f94a761910154d9d42ee4cYusuf Ozuysal}
359