diff --git a/BUILD.gn b/BUILD.gn
index 7b5bd9b28b5910..7fe7c7296bcc16 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -384,10 +384,10 @@ group("gn_all") {
"//chrome/android:chrome_public_apk",
"//chrome/android:chrome_public_test_apk",
"//chrome/android/features/media_router:media_router_junit_tests",
+ "//chrome/browser/android/examples/custom_tabs_client:custom_tabs_client_example_apk",
"//chrome/browser/android/examples/partner_browser_customizations_provider:partner_browser_customizations_example_apk",
"//chrome/test/chromedriver/test/webview_shell:chromedriver_webview_shell_apk",
"//content/shell/android:content_shell_test_apk",
- "//third_party/custom_tabs_client:custom_tabs_client_example_apk",
]
}
diff --git a/DEPS b/DEPS
index 9d1ad3ff9fbd31..a62b2ece848aaf 100644
--- a/DEPS
+++ b/DEPS
@@ -871,11 +871,6 @@ deps = {
'condition': 'checkout_linux',
},
- 'src/third_party/custom_tabs_client/src': {
- 'url': Var('chromium_git') + '/custom-tabs-client.git' + '@' + 'a633542d9854151eb4f0bfd1d93da88f5934a11a',
- 'condition': 'checkout_android',
- },
-
'src/third_party/depot_tools':
Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '19d4809e112652f918494840bab819603b0a2816',
diff --git a/chrome/browser/android/examples/custom_tabs_client/BUILD.gn b/chrome/browser/android/examples/custom_tabs_client/BUILD.gn
new file mode 100644
index 00000000000000..48d7238251b2d7
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/BUILD.gn
@@ -0,0 +1,76 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/android/rules.gni")
+
+android_resources("chrome_tabs_client_example_apk_resources") {
+ sources = [
+ "src/res/anim/slide_in_left.xml",
+ "src/res/anim/slide_in_right.xml",
+ "src/res/anim/slide_out_left.xml",
+ "src/res/anim/slide_out_right.xml",
+ "src/res/drawable-hdpi/ic_arrow_back.png",
+ "src/res/drawable-hdpi/ic_launcher.png",
+ "src/res/drawable-hdpi/ic_notification_icon.png",
+ "src/res/drawable-hdpi/ic_play.png",
+ "src/res/drawable-hdpi/ic_share.png",
+ "src/res/drawable-hdpi/ic_stop.png",
+ "src/res/drawable-mdpi/ic_arrow_back.png",
+ "src/res/drawable-mdpi/ic_launcher.png",
+ "src/res/drawable-mdpi/ic_notification_icon.png",
+ "src/res/drawable-mdpi/ic_play.png",
+ "src/res/drawable-mdpi/ic_share.png",
+ "src/res/drawable-mdpi/ic_stop.png",
+ "src/res/drawable-xhdpi/ic_arrow_back.png",
+ "src/res/drawable-xhdpi/ic_launcher.png",
+ "src/res/drawable-xhdpi/ic_notification_icon.png",
+ "src/res/drawable-xhdpi/ic_play.png",
+ "src/res/drawable-xhdpi/ic_share.png",
+ "src/res/drawable-xhdpi/ic_stop.png",
+ "src/res/drawable-xxhdpi/cover.jpg",
+ "src/res/drawable-xxhdpi/ic_arrow_back.png",
+ "src/res/drawable-xxhdpi/ic_launcher.png",
+ "src/res/drawable-xxhdpi/ic_notification_icon.png",
+ "src/res/drawable-xxhdpi/ic_play.png",
+ "src/res/drawable-xxhdpi/ic_share.png",
+ "src/res/drawable-xxhdpi/ic_stop.png",
+ "src/res/drawable-xxxhdpi/ic_arrow_back.png",
+ "src/res/drawable-xxxhdpi/ic_launcher.png",
+ "src/res/drawable-xxxhdpi/ic_share.png",
+ "src/res/layout/main.xml",
+ "src/res/layout/remote_view.xml",
+ "src/res/raw/amazing_grace.mp3",
+ "src/res/values/strings.xml",
+ ]
+ android_manifest = "src/AndroidManifest.xml"
+ custom_package = "org.chromium.customtabsclient"
+ deps = [ "//third_party/android_deps:android_support_v7_appcompat_java" ]
+}
+
+android_apk("custom_tabs_client_example_apk") {
+ sources = [
+ "src/java/org/chromium/customtabsclient/BottomBarManager.java",
+ "src/java/org/chromium/customtabsclient/BrowserActionsReceiver.java",
+ "src/java/org/chromium/customtabsclient/MainActivity.java",
+ "src/java/org/chromium/customtabsclient/SessionHelper.java",
+ "src/java/org/chromium/customtabsclient/shared/CustomTabsHelper.java",
+ "src/java/org/chromium/customtabsclient/shared/KeepAliveService.java",
+ "src/java/org/chromium/customtabsclient/shared/ServiceConnection.java",
+ "src/java/org/chromium/customtabsclient/shared/ServiceConnectionCallback.java",
+ ]
+
+ android_manifest = "src/AndroidManifest.xml"
+ min_sdk_version = 19
+ target_sdk_version = 21
+ apk_name = "CustomTabsClientExample"
+
+ deps = [
+ ":chrome_tabs_client_example_apk_resources",
+ "//third_party/android_deps:android_support_v7_appcompat_java",
+ "//third_party/android_deps:androidx_annotation_annotation_java",
+ "//third_party/android_deps:androidx_appcompat_appcompat_java",
+ "//third_party/android_deps:androidx_lifecycle_lifecycle_common_java",
+ "//third_party/android_sdk/androidx_browser:androidx_browser_java",
+ ]
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/OWNERS b/chrome/browser/android/examples/custom_tabs_client/OWNERS
new file mode 100644
index 00000000000000..0922ed2dacf90f
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/OWNERS
@@ -0,0 +1,4 @@
+file://chrome/android/java/src/org/chromium/chrome/browser/customtabs/OWNERS
+
+# COMPONENT: UI>Browser>Mobile>CustomTabs
+# OS: Android
\ No newline at end of file
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/AndroidManifest.xml b/chrome/browser/android/examples/custom_tabs_client/src/AndroidManifest.xml
new file mode 100644
index 00000000000000..43883a02313f33
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/AndroidManifest.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/BottomBarManager.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/BottomBarManager.java
new file mode 100644
index 00000000000000..7ad35749a81f7d
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/BottomBarManager.java
@@ -0,0 +1,86 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.customtabsclient;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.media.MediaPlayer;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+
+import androidx.browser.customtabs.CustomTabsIntent;
+import androidx.browser.customtabs.CustomTabsSession;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * A {@link BroadcastReceiver} that manages the interaction with the active Custom Tab.
+ */
+public class BottomBarManager extends BroadcastReceiver {
+ private static WeakReference sMediaPlayerWeakRef;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int clickedId = intent.getIntExtra(CustomTabsIntent.EXTRA_REMOTEVIEWS_CLICKED_ID, -1);
+ Toast.makeText(context, "Current URL " + intent.getDataString() + "\nClicked id "
+ + clickedId, Toast.LENGTH_SHORT).show();
+
+ CustomTabsSession session = SessionHelper.getCurrentSession();
+ if (session == null) return;
+
+ if (clickedId == R.id.play_pause) {
+ MediaPlayer player = sMediaPlayerWeakRef.get();
+ if (player != null) {
+ boolean isPlaying = player.isPlaying();
+ if (isPlaying) player.pause();
+ else player.start();
+ // Update the play/stop icon to respect the current state.
+ session.setSecondaryToolbarViews(createRemoteViews(context, isPlaying),
+ getClickableIDs(), getOnClickPendingIntent(context));
+ }
+ } else if (clickedId == R.id.cover) {
+ // Clicking on the cover image will dismiss the bottom bar.
+ session.setSecondaryToolbarViews(null, null, null);
+ }
+ }
+
+ /**
+ * Creates a RemoteViews that will be shown as the bottom bar of the custom tab.
+ * @param showPlayIcon If true, a play icon will be shown, otherwise show a pause icon.
+ * @return The created RemoteViews instance.
+ */
+ public static RemoteViews createRemoteViews(Context context, boolean showPlayIcon) {
+ RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.remote_view);
+
+ int iconRes = showPlayIcon ? R.drawable.ic_play : R.drawable.ic_stop;
+ remoteViews.setImageViewResource(R.id.play_pause, iconRes);
+ return remoteViews;
+ }
+
+ /**
+ * @return A list of View ids, the onClick event of which is handled by Custom Tab.
+ */
+ public static int[] getClickableIDs() {
+ return new int[]{R.id.play_pause, R.id.cover};
+ }
+
+ /**
+ * @return The PendingIntent that will be triggered when the user clicks on the Views listed by
+ * {@link BottomBarManager#getClickableIDs()}.
+ */
+ public static PendingIntent getOnClickPendingIntent(Context context) {
+ Intent broadcastIntent = new Intent(context, BottomBarManager.class);
+ return PendingIntent.getBroadcast(context, 0, broadcastIntent, 0);
+ }
+
+ /**
+ * Sets the {@link MediaPlayer} to be used when the user clicks on the RemoteViews.
+ */
+ public static void setMediaPlayer(MediaPlayer player) {
+ sMediaPlayerWeakRef = new WeakReference<>(player);
+ }
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/BrowserActionsReceiver.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/BrowserActionsReceiver.java
new file mode 100644
index 00000000000000..93f67529a47dae
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/BrowserActionsReceiver.java
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.customtabsclient;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.widget.Toast;
+
+/**
+ * A {@link BroadcastReceiver} that handles the callback if default menu items are chosen from
+ * Browser Actions.
+ */
+public class BrowserActionsReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String toastMsg = "Chosen item Id: " + intent.getDataString();
+ Toast.makeText(context, toastMsg, Toast.LENGTH_SHORT).show();
+ }
+}
\ No newline at end of file
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java
new file mode 100644
index 00000000000000..d67d86b03f3710
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/MainActivity.java
@@ -0,0 +1,298 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.customtabsclient;
+
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.v7.app.AppCompatActivity;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.browser.customtabs.CustomTabsCallback;
+import androidx.browser.customtabs.CustomTabsClient;
+import androidx.browser.customtabs.CustomTabsIntent;
+import androidx.browser.customtabs.CustomTabsServiceConnection;
+import androidx.browser.customtabs.CustomTabsSession;
+
+import org.chromium.customtabsclient.shared.CustomTabsHelper;
+import org.chromium.customtabsclient.shared.ServiceConnection;
+import org.chromium.customtabsclient.shared.ServiceConnectionCallback;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Example client activity for using Chrome Custom Tabs.
+ */
+public class MainActivity
+ extends AppCompatActivity implements OnClickListener, ServiceConnectionCallback {
+ private static final String TAG = "CustomTabsClientExample";
+ private static final String TOOLBAR_COLOR = "#ef6c00";
+
+ private EditText mEditText;
+ private CustomTabsSession mCustomTabsSession;
+ private CustomTabsClient mClient;
+ private CustomTabsServiceConnection mConnection;
+ private String mPackageNameToBind;
+ private Button mConnectButton;
+ private Button mWarmupButton;
+ private Button mMayLaunchButton;
+ private Button mLaunchButton;
+ private MediaPlayer mMediaPlayer;
+
+ /**
+ * Once per second, asks the framework for the process importance, and logs any change.
+ */
+ private Runnable mLogImportance = new Runnable() {
+ private int mPreviousImportance = -1;
+ private boolean mPreviousServiceInUse = false;
+ private Handler mHandler = new Handler(Looper.getMainLooper());
+
+ @Override
+ public void run() {
+ ActivityManager.RunningAppProcessInfo state =
+ new ActivityManager.RunningAppProcessInfo();
+ ActivityManager.getMyMemoryState(state);
+ int importance = state.importance;
+ boolean serviceInUse = state.importanceReasonCode
+ == ActivityManager.RunningAppProcessInfo.REASON_SERVICE_IN_USE;
+ if (importance != mPreviousImportance || serviceInUse != mPreviousServiceInUse) {
+ mPreviousImportance = importance;
+ mPreviousServiceInUse = serviceInUse;
+ String message = "New importance = " + importance;
+ if (serviceInUse) message += " (Reason: Service in use)";
+ Log.w(TAG, message);
+ }
+ mHandler.postDelayed(this, 1000);
+ }
+ };
+
+ private static class NavigationCallback extends CustomTabsCallback {
+ @Override
+ public void onNavigationEvent(int navigationEvent, Bundle extras) {
+ Log.w(TAG, "onNavigationEvent: Code = " + navigationEvent);
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+ mEditText = (EditText) findViewById(R.id.edit);
+ mConnectButton = (Button) findViewById(R.id.connect_button);
+ mWarmupButton = (Button) findViewById(R.id.warmup_button);
+ mMayLaunchButton = (Button) findViewById(R.id.may_launch_button);
+ mLaunchButton = (Button) findViewById(R.id.launch_button);
+ Spinner spinner = (Spinner) findViewById(R.id.spinner);
+ mEditText.requestFocus();
+ mConnectButton.setOnClickListener(this);
+ mWarmupButton.setOnClickListener(this);
+ mMayLaunchButton.setOnClickListener(this);
+ mLaunchButton.setOnClickListener(this);
+ mMediaPlayer = MediaPlayer.create(this, R.raw.amazing_grace);
+ findViewById(R.id.register_twa_service).setOnClickListener(this);
+
+ Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
+ PackageManager pm = getPackageManager();
+ List resolvedActivityList = pm.queryIntentActivities(
+ activityIntent, PackageManager.MATCH_ALL);
+ List> packagesSupportingCustomTabs = new ArrayList<>();
+ for (ResolveInfo info : resolvedActivityList) {
+ Intent serviceIntent = new Intent();
+ serviceIntent.setAction("android.support.customtabs.action.CustomTabsService");
+ serviceIntent.setPackage(info.activityInfo.packageName);
+ if (pm.resolveService(serviceIntent, 0) != null) {
+ packagesSupportingCustomTabs.add(
+ Pair.create(info.loadLabel(pm).toString(), info.activityInfo.packageName));
+ }
+ }
+
+ final ArrayAdapter> adapter = new ArrayAdapter>(
+ this, 0, packagesSupportingCustomTabs) {
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View view = convertView;
+ if (view == null) {
+ view = LayoutInflater.from(MainActivity.this).inflate(
+ android.R.layout.simple_list_item_2, parent, false);
+ }
+ Pair data = getItem(position);
+ ((TextView) view.findViewById(android.R.id.text1)).setText(data.first);
+ ((TextView) view.findViewById(android.R.id.text2)).setText(data.second);
+ return view;
+ }
+
+ @Override
+ public View getDropDownView(int position, View convertView, ViewGroup parent) {
+ return getView(position, convertView, parent);
+ }
+ };
+ spinner.setAdapter(adapter);
+ spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ Pair item = adapter.getItem(position);
+ if (TextUtils.isEmpty(item.second)) {
+ onNothingSelected(parent);
+ return;
+ }
+ mPackageNameToBind = item.second;
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {
+ mPackageNameToBind = null;
+ }
+ });
+
+ mLogImportance.run();
+ }
+
+ @Override
+ protected void onDestroy() {
+ unbindCustomTabsService();
+ super.onDestroy();
+ }
+
+ private CustomTabsSession getSession() {
+ if (mClient == null) {
+ mCustomTabsSession = null;
+ } else if (mCustomTabsSession == null) {
+ mCustomTabsSession = mClient.newSession(new NavigationCallback());
+ SessionHelper.setCurrentSession(mCustomTabsSession);
+ }
+ return mCustomTabsSession;
+ }
+
+ private void bindCustomTabsService() {
+ if (mClient != null) return;
+ if (TextUtils.isEmpty(mPackageNameToBind)) {
+ mPackageNameToBind = CustomTabsHelper.getPackageNameToUse(this);
+ if (mPackageNameToBind == null) return;
+ }
+ mConnection = new ServiceConnection(this);
+ boolean ok = CustomTabsClient.bindCustomTabsService(this, mPackageNameToBind, mConnection);
+ if (ok) {
+ mConnectButton.setEnabled(false);
+ } else {
+ mConnection = null;
+ }
+ }
+
+ private void unbindCustomTabsService() {
+ if (mConnection == null) return;
+ unbindService(mConnection);
+ mClient = null;
+ mCustomTabsSession = null;
+ }
+
+ @Override
+ public void onClick(View v) {
+ String url = mEditText.getText().toString();
+ int viewId = v.getId();
+
+ if (viewId == R.id.connect_button) {
+ bindCustomTabsService();
+ } else if (viewId == R.id.warmup_button) {
+ boolean success = false;
+ if (mClient != null) success = mClient.warmup(0);
+ if (!success) mWarmupButton.setEnabled(false);
+ } else if (viewId == R.id.may_launch_button) {
+ CustomTabsSession session = getSession();
+ boolean success = false;
+ if (mClient != null) success = session.mayLaunchUrl(Uri.parse(url), null, null);
+ if (!success) mMayLaunchButton.setEnabled(false);
+ } else if (viewId == R.id.launch_button) {
+ CustomTabsSession session = getSession();
+ CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(session);
+ builder.setToolbarColor(Color.parseColor(TOOLBAR_COLOR)).setShowTitle(true);
+ prepareMenuItems(builder);
+ prepareActionButton(builder);
+ if (session != null) prepareBottombar(builder);
+ builder.setStartAnimations(this, R.anim.slide_in_right, R.anim.slide_out_left);
+ builder.setExitAnimations(this, R.anim.slide_in_left, R.anim.slide_out_right);
+ builder.setCloseButtonIcon(
+ BitmapFactory.decodeResource(getResources(), R.drawable.ic_arrow_back));
+ CustomTabsIntent customTabsIntent = builder.build();
+ if (session != null) {
+ CustomTabsHelper.addKeepAliveExtra(this, customTabsIntent.intent);
+ } else {
+ if (!TextUtils.isEmpty(mPackageNameToBind)) {
+ customTabsIntent.intent.setPackage(mPackageNameToBind);
+ }
+ }
+ customTabsIntent.launchUrl(this, Uri.parse(url));
+ }
+ }
+
+ private void prepareMenuItems(CustomTabsIntent.Builder builder) {
+ Intent menuIntent = new Intent();
+ menuIntent.setClass(getApplicationContext(), this.getClass());
+ // Optional animation configuration when the user clicks menu items.
+ Bundle menuBundle = ActivityOptions.makeCustomAnimation(this, android.R.anim.slide_in_left,
+ android.R.anim.slide_out_right).toBundle();
+ PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, menuIntent, 0,
+ menuBundle);
+ builder.addMenuItem("Menu entry 1", pi);
+ }
+
+ private void prepareActionButton(CustomTabsIntent.Builder builder) {
+ // An example intent that sends an email.
+ Intent actionIntent = new Intent(Intent.ACTION_SEND);
+ actionIntent.setType("*/*");
+ actionIntent.putExtra(Intent.EXTRA_EMAIL, "example@example.com");
+ actionIntent.putExtra(Intent.EXTRA_SUBJECT, "example");
+ PendingIntent pi = PendingIntent.getActivity(this, 0, actionIntent, 0);
+ Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.ic_share);
+ builder.setActionButton(icon, "send email", pi, true);
+ }
+
+ private void prepareBottombar(CustomTabsIntent.Builder builder) {
+ BottomBarManager.setMediaPlayer(mMediaPlayer);
+ builder.setSecondaryToolbarViews(BottomBarManager.createRemoteViews(this, true),
+ BottomBarManager.getClickableIDs(), BottomBarManager.getOnClickPendingIntent(this));
+ }
+
+ @Override
+ public void onServiceConnected(CustomTabsClient client) {
+ mClient = client;
+ mConnectButton.setEnabled(false);
+ mWarmupButton.setEnabled(true);
+ mMayLaunchButton.setEnabled(true);
+ mLaunchButton.setEnabled(true);
+ }
+
+ @Override
+ public void onServiceDisconnected() {
+ mConnectButton.setEnabled(true);
+ mWarmupButton.setEnabled(false);
+ mMayLaunchButton.setEnabled(false);
+ mLaunchButton.setEnabled(false);
+ mClient = null;
+ }
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/SessionHelper.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/SessionHelper.java
new file mode 100644
index 00000000000000..98a46d145eb1cd
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/SessionHelper.java
@@ -0,0 +1,34 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.customtabsclient;
+
+import android.support.annotation.Nullable;
+
+import androidx.browser.customtabs.CustomTabsSession;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * A class that keeps tracks of the current {@link CustomTabsSession} and helps other components of
+ * the app to get access to the current session.
+ */
+public class SessionHelper {
+ private static WeakReference sCurrentSession;
+
+ /**
+ * @return The current {@link CustomTabsSession} object.
+ */
+ public static @Nullable CustomTabsSession getCurrentSession() {
+ return sCurrentSession == null ? null : sCurrentSession.get();
+ }
+
+ /**
+ * Sets the current session to the given one.
+ * @param session The current session.
+ */
+ public static void setCurrentSession(CustomTabsSession session) {
+ sCurrentSession = new WeakReference(session);
+ }
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/CustomTabsHelper.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/CustomTabsHelper.java
new file mode 100644
index 00000000000000..132769ce040ce3
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/CustomTabsHelper.java
@@ -0,0 +1,132 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.customtabsclient.shared;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class for Custom Tabs.
+ */
+public class CustomTabsHelper {
+ private static final String TAG = "CustomTabsHelper";
+ static final String STABLE_PACKAGE = "com.android.chrome";
+ static final String BETA_PACKAGE = "com.chrome.beta";
+ static final String DEV_PACKAGE = "com.chrome.dev";
+ static final String LOCAL_PACKAGE = "com.google.android.apps.chrome";
+ private static final String EXTRA_CUSTOM_TABS_KEEP_ALIVE =
+ "android.support.customtabs.extra.KEEP_ALIVE";
+ private static final String ACTION_CUSTOM_TABS_CONNECTION =
+ "android.support.customtabs.action.CustomTabsService";
+
+ private static String sPackageNameToUse;
+
+ private CustomTabsHelper() {}
+
+ public static void addKeepAliveExtra(Context context, Intent intent) {
+ Intent keepAliveIntent = new Intent().setClassName(
+ context.getPackageName(), KeepAliveService.class.getCanonicalName());
+ intent.putExtra(EXTRA_CUSTOM_TABS_KEEP_ALIVE, keepAliveIntent);
+ }
+
+ /**
+ * Goes through all apps that handle VIEW intents and have a warmup service. Picks
+ * the one chosen by the user if there is one, otherwise makes a best effort to return a
+ * valid package name.
+ *
+ * This is not threadsafe.
+ *
+ * @param context {@link Context} to use for accessing {@link PackageManager}.
+ * @return The package name recommended to use for connecting to custom tabs related components.
+ */
+ public static String getPackageNameToUse(Context context) {
+ if (sPackageNameToUse != null) return sPackageNameToUse;
+
+ PackageManager pm = context.getPackageManager();
+ // Get default VIEW intent handler.
+ Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com"));
+ ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0);
+ String defaultViewHandlerPackageName = null;
+ if (defaultViewHandlerInfo != null) {
+ defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName;
+ }
+
+ // Get all apps that can handle VIEW intents.
+ List resolvedActivityList = pm.queryIntentActivities(activityIntent, 0);
+ List packagesSupportingCustomTabs = new ArrayList<>();
+ for (ResolveInfo info : resolvedActivityList) {
+ Intent serviceIntent = new Intent();
+ serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION);
+ serviceIntent.setPackage(info.activityInfo.packageName);
+ if (pm.resolveService(serviceIntent, 0) != null) {
+ packagesSupportingCustomTabs.add(info.activityInfo.packageName);
+ }
+ }
+
+ // Now packagesSupportingCustomTabs contains all apps that can handle both VIEW intents
+ // and service calls.
+ if (packagesSupportingCustomTabs.isEmpty()) {
+ sPackageNameToUse = null;
+ } else if (packagesSupportingCustomTabs.size() == 1) {
+ sPackageNameToUse = packagesSupportingCustomTabs.get(0);
+ } else if (!TextUtils.isEmpty(defaultViewHandlerPackageName)
+ && !hasSpecializedHandlerIntents(context, activityIntent)
+ && packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) {
+ sPackageNameToUse = defaultViewHandlerPackageName;
+ } else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) {
+ sPackageNameToUse = STABLE_PACKAGE;
+ } else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) {
+ sPackageNameToUse = BETA_PACKAGE;
+ } else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) {
+ sPackageNameToUse = DEV_PACKAGE;
+ } else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) {
+ sPackageNameToUse = LOCAL_PACKAGE;
+ }
+ return sPackageNameToUse;
+ }
+
+ /**
+ * Used to check whether there is a specialized handler for a given intent.
+ * @param intent The intent to check with.
+ * @return Whether there is a specialized handler for the given intent.
+ */
+ private static boolean hasSpecializedHandlerIntents(Context context, Intent intent) {
+ try {
+ PackageManager pm = context.getPackageManager();
+ List handlers = pm.queryIntentActivities(
+ intent,
+ PackageManager.GET_RESOLVED_FILTER);
+ if (handlers == null || handlers.size() == 0) {
+ return false;
+ }
+ for (ResolveInfo resolveInfo : handlers) {
+ IntentFilter filter = resolveInfo.filter;
+ if (filter == null) continue;
+ if (filter.countDataAuthorities() == 0 || filter.countDataPaths() == 0) continue;
+ if (resolveInfo.activityInfo == null) continue;
+ return true;
+ }
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Runtime exception while getting specialized handlers");
+ }
+ return false;
+ }
+
+ /**
+ * @return All possible chrome package names that provide custom tabs feature.
+ */
+ public static String[] getPackages() {
+ return new String[]{"", STABLE_PACKAGE, BETA_PACKAGE, DEV_PACKAGE, LOCAL_PACKAGE};
+ }
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/KeepAliveService.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/KeepAliveService.java
new file mode 100644
index 00000000000000..3bde921bc627d2
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/KeepAliveService.java
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.customtabsclient.shared;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.IBinder;
+
+/**
+ * Empty service used by the custom tab to bind to, raising the application's importance.
+ */
+public class KeepAliveService extends Service {
+ private static final Binder sBinder = new Binder();
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return sBinder;
+ }
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/ServiceConnection.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/ServiceConnection.java
new file mode 100644
index 00000000000000..3de4ff2fd487d3
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/ServiceConnection.java
@@ -0,0 +1,37 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.customtabsclient.shared;
+
+import android.content.ComponentName;
+
+import androidx.browser.customtabs.CustomTabsClient;
+import androidx.browser.customtabs.CustomTabsServiceConnection;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Implementation for the CustomTabsServiceConnection that avoids leaking the
+ * ServiceConnectionCallback
+ */
+public class ServiceConnection extends CustomTabsServiceConnection {
+ // A weak reference to the ServiceConnectionCallback to avoid leaking it.
+ private WeakReference mConnectionCallback;
+
+ public ServiceConnection(ServiceConnectionCallback connectionCallback) {
+ mConnectionCallback = new WeakReference<>(connectionCallback);
+ }
+
+ @Override
+ public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) {
+ ServiceConnectionCallback connectionCallback = mConnectionCallback.get();
+ if (connectionCallback != null) connectionCallback.onServiceConnected(client);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ ServiceConnectionCallback connectionCallback = mConnectionCallback.get();
+ if (connectionCallback != null) connectionCallback.onServiceDisconnected();
+ }
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/ServiceConnectionCallback.java b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/ServiceConnectionCallback.java
new file mode 100644
index 00000000000000..dcb57a992bfbb9
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/java/org/chromium/customtabsclient/shared/ServiceConnectionCallback.java
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.customtabsclient.shared;
+
+import androidx.browser.customtabs.CustomTabsClient;
+
+/**
+ * Callback for events when connecting and disconnecting from Custom Tabs Service.
+ */
+public interface ServiceConnectionCallback {
+ /**
+ * Called when the service is connected.
+ * @param client a CustomTabsClient
+ */
+ void onServiceConnected(CustomTabsClient client);
+
+ /**
+ * Called when the service is disconnected.
+ */
+ void onServiceDisconnected();
+}
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_in_left.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_in_left.xml
new file mode 100644
index 00000000000000..373537bb30c092
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_in_left.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_in_right.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_in_right.xml
new file mode 100644
index 00000000000000..75d067596c018c
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_in_right.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_out_left.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_out_left.xml
new file mode 100644
index 00000000000000..6ce16766c00b86
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_out_left.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_out_right.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_out_right.xml
new file mode 100644
index 00000000000000..def11b24ae65e3
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/anim/slide_out_right.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_arrow_back.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_arrow_back.png
new file mode 100644
index 00000000000000..fe424468ef985f
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_arrow_back.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_launcher.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 00000000000000..2a258242898b56
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_launcher.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_notification_icon.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_notification_icon.png
new file mode 100644
index 00000000000000..c2c80d47a4aa24
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_notification_icon.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_play.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_play.png
new file mode 100644
index 00000000000000..8baf85aaabc640
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_play.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_share.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_share.png
new file mode 100644
index 00000000000000..b09a6926de5aa4
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_share.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_stop.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_stop.png
new file mode 100644
index 00000000000000..33fe92417c2e1b
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-hdpi/ic_stop.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_arrow_back.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_arrow_back.png
new file mode 100644
index 00000000000000..09040008e8d884
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_arrow_back.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_launcher.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 00000000000000..c38d44c5c7d740
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_launcher.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_notification_icon.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_notification_icon.png
new file mode 100644
index 00000000000000..9960b1bf6c62fe
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_notification_icon.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_play.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_play.png
new file mode 100644
index 00000000000000..000238c0c261a4
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_play.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_share.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_share.png
new file mode 100644
index 00000000000000..e944fd70c42861
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_share.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_stop.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_stop.png
new file mode 100644
index 00000000000000..4315863d4afce3
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-mdpi/ic_stop.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_arrow_back.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_arrow_back.png
new file mode 100644
index 00000000000000..ebc826c225cfe4
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_arrow_back.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_launcher.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 00000000000000..b12097ce144420
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_notification_icon.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_notification_icon.png
new file mode 100644
index 00000000000000..00f5b4fbe6b585
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_notification_icon.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_play.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_play.png
new file mode 100644
index 00000000000000..e4d298d6dd3520
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_play.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_share.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_share.png
new file mode 100644
index 00000000000000..22a8783e70f014
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_share.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_stop.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_stop.png
new file mode 100644
index 00000000000000..7f24bf2dcdda55
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xhdpi/ic_stop.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/cover.jpg b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/cover.jpg
new file mode 100644
index 00000000000000..2f5cc5801361d1
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/cover.jpg differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_arrow_back.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_arrow_back.png
new file mode 100644
index 00000000000000..099f9edccdb817
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_arrow_back.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_launcher.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000000000..71b68abe0f3da1
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_launcher.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_notification_icon.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_notification_icon.png
new file mode 100644
index 00000000000000..c2c7d734408a9d
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_notification_icon.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_play.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_play.png
new file mode 100644
index 00000000000000..9f5d2b7bf39032
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_play.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_share.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_share.png
new file mode 100644
index 00000000000000..a35b3cd14af898
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_share.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_stop.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_stop.png
new file mode 100644
index 00000000000000..82a4cccbcaa230
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxhdpi/ic_stop.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_arrow_back.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_arrow_back.png
new file mode 100644
index 00000000000000..fb06e1d485ce12
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_arrow_back.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_launcher.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000000000..32443beb569b66
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_launcher.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_share.png b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_share.png
new file mode 100644
index 00000000000000..e351c7beb089e9
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/drawable-xxxhdpi/ic_share.png differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/layout/main.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/layout/main.xml
new file mode 100644
index 00000000000000..141866ac98edf4
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/layout/main.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/layout/remote_view.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/layout/remote_view.xml
new file mode 100644
index 00000000000000..a740941c27b2aa
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/layout/remote_view.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/raw/amazing_grace.mp3 b/chrome/browser/android/examples/custom_tabs_client/src/res/raw/amazing_grace.mp3
new file mode 100644
index 00000000000000..08009a6a7c35fb
Binary files /dev/null and b/chrome/browser/android/examples/custom_tabs_client/src/res/raw/amazing_grace.mp3 differ
diff --git a/chrome/browser/android/examples/custom_tabs_client/src/res/values/strings.xml b/chrome/browser/android/examples/custom_tabs_client/src/res/values/strings.xml
new file mode 100644
index 00000000000000..79cd0b5b1dd9b0
--- /dev/null
+++ b/chrome/browser/android/examples/custom_tabs_client/src/res/values/strings.xml
@@ -0,0 +1,25 @@
+
+
+
+ Chrome Custom Tabs Example
+ Please type the url here.
+ Warmup Chrome
+ May Launch URL
+ Launch URL in a Chrome Custom Tab
+ Connect to the service
+ Launch URL in Browser Actions Context Menu
+ Register TrustedWebActivityService
+
diff --git a/third_party/custom_tabs_client/testing_with_chromium.md b/chrome/browser/android/examples/custom_tabs_client/testing_with_chromium.md
similarity index 100%
rename from third_party/custom_tabs_client/testing_with_chromium.md
rename to chrome/browser/android/examples/custom_tabs_client/testing_with_chromium.md
diff --git a/third_party/custom_tabs_client/BUILD.gn b/third_party/custom_tabs_client/BUILD.gn
deleted file mode 100644
index c2950ac107d288..00000000000000
--- a/third_party/custom_tabs_client/BUILD.gn
+++ /dev/null
@@ -1,156 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/android/rules.gni")
-
-android_resources("chrome_tabs_client_example_apk_resources") {
- sources = [
- "src/Application/src/main/res/anim/slide_in_left.xml",
- "src/Application/src/main/res/anim/slide_in_right.xml",
- "src/Application/src/main/res/anim/slide_out_left.xml",
- "src/Application/src/main/res/anim/slide_out_right.xml",
- "src/Application/src/main/res/drawable-hdpi/ic_arrow_back.png",
- "src/Application/src/main/res/drawable-hdpi/ic_launcher.png",
- "src/Application/src/main/res/drawable-hdpi/ic_notification_icon.png",
- "src/Application/src/main/res/drawable-hdpi/ic_play.png",
- "src/Application/src/main/res/drawable-hdpi/ic_share.png",
- "src/Application/src/main/res/drawable-hdpi/ic_stop.png",
- "src/Application/src/main/res/drawable-mdpi/ic_arrow_back.png",
- "src/Application/src/main/res/drawable-mdpi/ic_launcher.png",
- "src/Application/src/main/res/drawable-mdpi/ic_notification_icon.png",
- "src/Application/src/main/res/drawable-mdpi/ic_play.png",
- "src/Application/src/main/res/drawable-mdpi/ic_share.png",
- "src/Application/src/main/res/drawable-mdpi/ic_stop.png",
- "src/Application/src/main/res/drawable-xhdpi/ic_arrow_back.png",
- "src/Application/src/main/res/drawable-xhdpi/ic_launcher.png",
- "src/Application/src/main/res/drawable-xhdpi/ic_notification_icon.png",
- "src/Application/src/main/res/drawable-xhdpi/ic_play.png",
- "src/Application/src/main/res/drawable-xhdpi/ic_share.png",
- "src/Application/src/main/res/drawable-xhdpi/ic_stop.png",
- "src/Application/src/main/res/drawable-xxhdpi/cover.jpg",
- "src/Application/src/main/res/drawable-xxhdpi/ic_arrow_back.png",
- "src/Application/src/main/res/drawable-xxhdpi/ic_launcher.png",
- "src/Application/src/main/res/drawable-xxhdpi/ic_notification_icon.png",
- "src/Application/src/main/res/drawable-xxhdpi/ic_play.png",
- "src/Application/src/main/res/drawable-xxhdpi/ic_share.png",
- "src/Application/src/main/res/drawable-xxhdpi/ic_stop.png",
- "src/Application/src/main/res/drawable-xxxhdpi/ic_arrow_back.png",
- "src/Application/src/main/res/drawable-xxxhdpi/ic_launcher.png",
- "src/Application/src/main/res/drawable-xxxhdpi/ic_share.png",
- "src/Application/src/main/res/layout/main.xml",
- "src/Application/src/main/res/layout/remote_view.xml",
- "src/Application/src/main/res/raw/amazing_grace.mp3",
- "src/Application/src/main/res/values/strings.xml",
- ]
- android_manifest = "src/Application/src/main/AndroidManifest.xml"
- custom_package = "org.chromium.customtabsclient"
- deps = [ "//third_party/android_deps:android_support_v7_appcompat_java" ]
-}
-
-android_resources("custom_tabs_support_resources") {
- sources = [
- "src/customtabs/res/layout/browser_actions_context_menu_page.xml",
- "src/customtabs/res/layout/browser_actions_context_menu_row.xml",
- "src/customtabs/res/values/colors.xml",
- "src/customtabs/res/values/dimens.xml",
- "src/customtabs/res/values/strings.xml",
- "src/customtabs/res/xml/image_share_filepaths.xml",
- ]
- android_manifest = "src/customtabs/AndroidManifest.xml"
- custom_package = "android.support.customtabs"
-}
-
-android_apk("custom_tabs_client_example_apk") {
- skip_jetify = true
- sources = [
- "src/Application/src/main/java/org/chromium/customtabsclient/BottomBarManager.java",
- "src/Application/src/main/java/org/chromium/customtabsclient/BrowserActionsReceiver.java",
- "src/Application/src/main/java/org/chromium/customtabsclient/MainActivity.java",
- "src/Application/src/main/java/org/chromium/customtabsclient/SessionHelper.java",
- ]
- android_manifest = "src/Application/src/main/AndroidManifest.xml"
- min_sdk_version = 16
- target_sdk_version = 21
- apk_name = "CustomTabsClientExample"
- deps = [
- ":chrome_tabs_client_example_apk_resources",
- ":custom_tabs_client_shared_java",
- ":custom_tabs_support_java",
- "//third_party/android_deps:android_arch_lifecycle_common_java",
- "//third_party/android_deps:android_support_v7_appcompat_java",
- "//third_party/android_deps:com_android_support_appcompat_v7_java",
- "//third_party/android_deps:com_android_support_support_annotations_java",
- ]
- chromium_code = false
-}
-
-android_library("custom_tabs_client_shared_java") {
- skip_jetify = true
- sources = [
- "src/shared/src/main/java/org/chromium/customtabsclient/shared/CustomTabsHelper.java",
- "src/shared/src/main/java/org/chromium/customtabsclient/shared/KeepAliveService.java",
- "src/shared/src/main/java/org/chromium/customtabsclient/shared/ServiceConnection.java",
- "src/shared/src/main/java/org/chromium/customtabsclient/shared/ServiceConnectionCallback.java",
- ]
-
- deps = [ ":custom_tabs_support_java" ]
- chromium_code = false
-}
-
-android_library("custom_tabs_support_java") {
- skip_jetify = true
- sources = [
- "src/customtabs/src/android/support/customtabs/CustomTabColorSchemeParams.java",
- "src/customtabs/src/android/support/customtabs/CustomTabsCallback.java",
- "src/customtabs/src/android/support/customtabs/CustomTabsClient.java",
- "src/customtabs/src/android/support/customtabs/CustomTabsIntent.java",
- "src/customtabs/src/android/support/customtabs/CustomTabsService.java",
- "src/customtabs/src/android/support/customtabs/CustomTabsServiceConnection.java",
- "src/customtabs/src/android/support/customtabs/CustomTabsSession.java",
- "src/customtabs/src/android/support/customtabs/CustomTabsSessionToken.java",
- "src/customtabs/src/android/support/customtabs/PostMessageBackend.java",
- "src/customtabs/src/android/support/customtabs/PostMessageService.java",
- "src/customtabs/src/android/support/customtabs/PostMessageServiceConnection.java",
- "src/customtabs/src/android/support/customtabs/TrustedWebUtils.java",
- "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionItem.java",
- "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionsFallbackMenuAdapter.java",
- "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionsFallbackMenuDialog.java",
- "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionsFallbackMenuUi.java",
- "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionsFallbackMenuView.java",
- "src/customtabs/src/android/support/customtabs/browseractions/BrowserActionsIntent.java",
- "src/customtabs/src/android/support/customtabs/browseractions/BrowserServiceFileProvider.java",
- "src/customtabs/src/android/support/customtabs/browseractions/BrowserServiceImageReadTask.java",
- "src/customtabs/src/android/support/customtabs/trusted/TrustedWebActivityBuilder.java",
- "src/customtabs/src/android/support/customtabs/trusted/TrustedWebActivityService.java",
- "src/customtabs/src/android/support/customtabs/trusted/TrustedWebActivityServiceConnectionManager.java",
- "src/customtabs/src/android/support/customtabs/trusted/TrustedWebActivityServiceWrapper.java",
- ]
- deps = [
- ":custom_tabs_support_resources",
-
- # TODO (bjoyce): Restore to android_support_v7_appcompat_java once source
- # files are manually written to androidx crbug.com/1047843.
- # "//third_party/android_deps:android_support_v7_appcompat_java",
- "//third_party/android_deps:com_android_support_appcompat_v7_java_orig",
- "//third_party/android_deps:com_android_support_collections_java_orig",
- "//third_party/android_deps:com_android_support_interpolator_java",
- "//third_party/android_deps:com_android_support_support_annotations_java",
- "//third_party/android_deps:com_android_support_support_compat_java",
- ]
- srcjar_deps = [ ":chrome_custom_tabs_service_aidl" ]
- android_manifest_for_lint = "src/customtabs/AndroidManifest.xml"
- chromium_code = false
-}
-
-android_aidl("chrome_custom_tabs_service_aidl") {
- interface_file = "common.aidl"
-
- java_in_dir = "src/customtabs/src/android/support/customtabs"
- sources = [
- "$java_in_dir/ICustomTabsCallback.aidl",
- "$java_in_dir/ICustomTabsService.aidl",
- "$java_in_dir/IPostMessageService.aidl",
- "$java_in_dir/trusted/ITrustedWebActivityService.aidl",
- ]
-}
diff --git a/third_party/custom_tabs_client/LICENSE b/third_party/custom_tabs_client/LICENSE
deleted file mode 100644
index 67db8588217f26..00000000000000
--- a/third_party/custom_tabs_client/LICENSE
+++ /dev/null
@@ -1,175 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
diff --git a/third_party/custom_tabs_client/OWNERS b/third_party/custom_tabs_client/OWNERS
deleted file mode 100644
index e341d8215aea7b..00000000000000
--- a/third_party/custom_tabs_client/OWNERS
+++ /dev/null
@@ -1,7 +0,0 @@
-lizeb@chromium.org
-peconn@chromium.org
-yusufo@chromium.org
-
-per-file *.aidl=set noparent
-per-file *.aidl=file://ipc/SECURITY_OWNERS
-# COMPONENT: UI>Browser>Mobile>CustomTabs
diff --git a/third_party/custom_tabs_client/README.chromium b/third_party/custom_tabs_client/README.chromium
deleted file mode 100644
index 0bf829be1c8d21..00000000000000
--- a/third_party/custom_tabs_client/README.chromium
+++ /dev/null
@@ -1,26 +0,0 @@
-Name: Chrome Custom Tabs - Example and Usage
-Short Name: Chrome Custom Tabs Client
-URL: https://chromium.googlesource.com/external/github.com/GoogleChrome/custom-tabs-client
-Version: unknown
-License: Apache 2.0
-Security Critical: yes
-License Android Compatible: yes
-
-Description:
-This presents an example application using Chrome Custom Tabs, and a possible
-usage of both the intent and the background service APIs. It covers UI
-customization, callback setup, pre-warming and pre-fetching, and lifecycle
-management. Also inside demos there is another application that launches
-custom tabs in different modes.
-
-The example applicaton also presents how to use Browser Actions, including
-creating request intent and adding custom items.
-
-The actual code that Chromium builds from is in
-//third_party/android_sdk/androidx_browser, this subdirectory is kept around
-for the example app (the custom_tabs_client_example_apk target).
-
-TODO(peconn): Get rid of src/customtabs and depend instead on
-androidx_browser.
-
-Local Modifications: None
diff --git a/third_party/custom_tabs_client/common.aidl b/third_party/custom_tabs_client/common.aidl
deleted file mode 100644
index 5566e8ca02a74b..00000000000000
--- a/third_party/custom_tabs_client/common.aidl
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-interface android.support.customtabs.ICustomTabsService;
-interface android.support.customtabs.ICustomTabsCallback;
-interface android.support.customtabs.IPostMessageService;