Adding custom interactivity

Sebastian Benz
Sebastian Benz

This guide explains how to add custom interactivity to Custom Tabs.

Enable the default share action

If you don't provide a custom share action, it is a good idea to enable the browser's default share action in the overflow menu to make it easier for users to share a link to the content they are seeing:

    CustomTabsIntent.Builder intentBuilder = new CustomTabsIntent.Builder();
    intentBuilder.setShareState(CustomTabsIntent.SHARE_STATE_ON);

Add a custom action button

For important actions, the Custom Tab toolbar lets you integrate a custom action button, which can either have a text label or a custom icon. The icon should be 24dp in height and 24-48 dp in width.

Custom Tab with a custom share action

For example, you can add a custom share action to the toolbar. To do this, create a BroadcastReceiver which gets called when the user clicks on the share action in the Custom Tab.

Register the BroadCastReceiver in the AndroidManifest.xml file:

<application …>
  <receiver android:name=".ShareBroadcastReceiver" />
</application>

Then add a new class, ShareBroadcastReceiver. In the onReceive() method, extract the currently displayed URL from the intent and trigger a send intent.

public class ShareBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String url = intent.getDataString();
        Intent sendIntent = new Intent();
        sendIntent.setAction(Intent.ACTION_SEND);
        sendIntent.putExtra(Intent.EXTRA_TEXT, url);
        sendIntent.setType("text/plain");
        Intent shareIntent = Intent.createChooser(sendIntent, null);
        shareIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(shareIntent);
    }
}

Now, create a PendingIntent for ShareBroadcast and register it via setActionButton(). Pass the pending intent together with the icon and the description.

String shareDescription = getString(R.string.label_action_share);
Bitmap shareIcon = BitmapFactory.decodeResource(getResources(),
       android.R.drawable.ic_menu_share);

// Create a PendingIntent to your BroadCastReceiver implementation
Intent actionIntent = new Intent(
       this.getApplicationContext(), ShareBroadcastReceiver.class);
PendingIntent pendingIntent =
       PendingIntent.getBroadcast(getApplicationContext(), 0 /* request code */, actionIntent, PendingIntent.FLAG_MUTABLE);          

//Set the pendingIntent as the action to be performed when the button is clicked.
CustomTabsIntent intentBuilder = new CustomTabsIntent.Builder()
    …
    .setActionButton(shareIcon, shareDescription, pendingIntent)
    .build();

Add custom menu items

A Custom Tab has as many as five default actions provided by the browser: "Forward", "Page Info", "Refresh", "Find in Page" and "Open in Browser". Additionally, you can add up to seven more. These menu items will be inserted between the icon row and the browser-provided items. (See the image below.) The actual number depends on the underlying browser implementation. (For example, with version 117 Chrome increased the number of menu items from five to seven.) So it is best to add the most important items first.

You can access your custom actions via the three dot menu in the top right corner:

Custom Tab with five custom menu items.

To add a menu item, call CustomTabsIntent.Builder.addMenuItem() with title and a PendingIntent. When the user taps on a menu item, the browser will fire the PendingIntent.

CustomTabsIntent intent = new CustomTabsIntent.Builder()
        ...
        .addMenuItem("Menu item 1", pendingIntent)
        .addMenuItem("Menu item 2", pendingIntent)
        .addMenuItem("Menu item 3", pendingIntent)
        .addMenuItem("Menu item 4", pendingIntent)
        .addMenuItem("Menu item 5", pendingIntent)
        .build();

Customize the close button

To better fit a Custom Tab into the flow of your app, customize the close button. If you want the user to feel like Custom Tabs is a modal dialog, use the default “X” button. If you want the user to feel the Custom Tab is part of the application flow, use the back arrow.

CustomTabsIntent.Builder intentBuilder = new CustomTabsIntent.Builder();
intentBuilder.setCloseButtonIcon(BitmapFactory.decodeResource(
    getResources(), R.drawable.ic_arrow_back));

Add a bottom toolbar

The bottom toolbar is a very flexible way to add more functionality to a Custom Tab.

Custom Tab with a bottom toolbar

By passing a RemoteViews object to CustomTabIntent.Builder.setSecondaryToolbarViews(), the bottom toolbar can be fully customized and dynamically updated.

First, declare a toolbar layout by creating a new layout file, res/layout/custom_tab_toolbar.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="center">

    <Button xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ct_toolbar_next"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:layout_margin="8dp"
        android:padding="8dp"
        android:paddingStart="16dp"
        android:paddingEnd="16dp"
        android:text="Next" />

    <Button xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ct_toolbar_previous"
        android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:layout_margin="8dp"
        android:padding="8dp"
        android:text="Previous" />
</LinearLayout>

The next step is to register a BroadcastReceiver, which handles toolbar interactions, in the AndroidManifest.xml file:

<application …>
  <receiver android:name=".CustomTabBottomToolbarBroadcastReceiver" />
</application>

Then implement the BroadcastReceiver, which will handle all interactions with the bottom toolbar:

public class BottomToolbarBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String url = intent.getDataString();
        int remoteViewId = intent.getIntExtra(EXTRA_REMOTEVIEWS_CLICKED_ID, -1);
        if (remoteViewId == R.id.ct_toolbar_previous) {
          // handle previous
        } else if (remoteViewId == R.id.ct_toolbar_next) {
          // handle next
        }
    }
}

Finally, register the toolbar:

// Create the pending intent
Intent actionIntent = new Intent(
       this.getApplicationContext(), BottomToolbarBroadcastReceiver.class);

PendingIntent pendingIntent =
       PendingIntent.getBroadcast(getApplicationContext(), 0 /* request code */, actionIntent, PendingIntent.FLAG_MUTABLE);          

// Pass the toolbar layout to the RemoteViews instance
RemoteViews secondaryToolbarViews = new RemoteViews(getPackageName(), R.layout.custom_tab_toolbar);
// All toolbar buttons
int[] clickableIds = {R.id.ct_toolbar_next, R.id.ct_toolbar_previous};

// Register the bottom toolbar when creating a new custom tab intent
CustomTabsIntent intent = new CustomTabsIntent.Builder()
    .setSecondaryToolbarViews(secondaryToolbarViews, clickableIds, toolbarPendingIntent)
    .build();

Bookmarks and download buttons

The bookmarks and download buttons in the three dot menu are enabled by default. To disable them, use the following code in CustomTabsIntent.Builder:

CustomTabsIntent customTabsIntent = new CustomTabsIntent.Builder()
    .setBookmarksButtonEnabled(false)
    .setDownloadButtonEnabled(false)
    .build();

Next up: Learn how to speed up loading web content in a Custom Tab.