1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org
.chromium
.chrome
.browser
.customtabs
;
7 import android
.content
.Intent
;
8 import android
.net
.Uri
;
9 import android
.text
.TextUtils
;
10 import android
.view
.MenuItem
;
11 import android
.view
.View
;
12 import android
.view
.View
.OnClickListener
;
13 import android
.view
.ViewGroup
;
15 import com
.google
.android
.apps
.chrome
.R
;
17 import org
.chromium
.base
.ApiCompatibilityUtils
;
18 import org
.chromium
.base
.VisibleForTesting
;
19 import org
.chromium
.chrome
.browser
.CompositorChromeActivity
;
20 import org
.chromium
.chrome
.browser
.IntentHandler
;
21 import org
.chromium
.chrome
.browser
.Tab
;
22 import org
.chromium
.chrome
.browser
.appmenu
.AppMenuHandler
;
23 import org
.chromium
.chrome
.browser
.appmenu
.AppMenuObserver
;
24 import org
.chromium
.chrome
.browser
.appmenu
.AppMenuPropertiesDelegate
;
25 import org
.chromium
.chrome
.browser
.compositor
.layouts
.LayoutManagerDocument
;
26 import org
.chromium
.chrome
.browser
.document
.BrandColorUtils
;
27 import org
.chromium
.chrome
.browser
.tabmodel
.SingleTabModelSelector
;
28 import org
.chromium
.chrome
.browser
.toolbar
.ToolbarControlContainer
;
29 import org
.chromium
.chrome
.browser
.toolbar
.ToolbarHelper
;
30 import org
.chromium
.chrome
.browser
.widget
.findinpage
.FindToolbarManager
;
31 import org
.chromium
.content_public
.browser
.LoadUrlParams
;
34 * The activity for custom tabs. It will be launched on top of a client's task.
36 public class CustomTabActivity
extends CompositorChromeActivity
{
37 private static CustomTabContentHandler sActiveContentHandler
;
39 private CustomTab mTab
;
40 private ToolbarHelper mToolbarHelper
;
41 private CustomTabAppMenuPropertiesDelegate mAppMenuPropertiesDelegate
;
42 private AppMenuHandler mAppMenuHandler
;
43 private FindToolbarManager mFindToolbarManager
;
44 private CustomTabIntentDataProvider mIntentDataProvider
;
45 private long mSessionId
;
46 private CustomTabContentHandler mCustomTabContentHandler
;
48 // This is to give the right package name while using the client's resources during an
49 // overridePendingTransition call.
50 // TODO(ianwen, yusufo): Figure out a solution to extract external resources without having to
51 // change the package name.
52 private boolean mShouldOverridePackage
;
55 * Sets the currently active {@link CustomTabContentHandler} in focus.
56 * @param contentHandler {@link CustomTabContentHandler} to set.
58 public static void setActiveContentHandler(CustomTabContentHandler contentHandler
) {
59 sActiveContentHandler
= contentHandler
;
63 * Used to check whether an incoming intent can be handled by the
64 * current {@link CustomTabContentHandler}.
65 * @return Whether the active {@link CustomTabContentHandler} has handled the intent.
67 public static boolean handleInActiveContentIfNeeded(Intent intent
) {
68 if (sActiveContentHandler
== null) return false;
70 long intentSessionId
= intent
.getLongExtra(
71 CustomTabIntentDataProvider
.EXTRA_CUSTOM_TABS_SESSION_ID
,
72 CustomTabIntentDataProvider
.INVALID_SESSION_ID
);
73 if (intentSessionId
== CustomTabIntentDataProvider
.INVALID_SESSION_ID
) return false;
75 if (sActiveContentHandler
.getSessionId() != intentSessionId
) return false;
76 String url
= IntentHandler
.getUrlFromIntent(intent
);
77 if (TextUtils
.isEmpty(url
)) return false;
78 sActiveContentHandler
.loadUrl(new LoadUrlParams(url
));
83 public void onStart() {
85 ChromeBrowserConnection
.getInstance(getApplication())
86 .keepAliveForSessionId(mIntentDataProvider
.getSessionId(),
87 mIntentDataProvider
.getKeepAliveServiceIntent());
91 public void onStop() {
93 ChromeBrowserConnection
.getInstance(getApplication())
94 .dontKeepAliveForSessionId(mIntentDataProvider
.getSessionId());
98 public void preInflationStartup() {
99 super.preInflationStartup();
100 setTabModelSelector(new SingleTabModelSelector(this, false, true));
101 mIntentDataProvider
= new CustomTabIntentDataProvider(getIntent(), this);
105 public void postInflationStartup() {
106 super.postInflationStartup();
107 ToolbarControlContainer controlContainer
=
108 ((ToolbarControlContainer
) findViewById(R
.id
.control_container
));
109 mAppMenuPropertiesDelegate
= new CustomTabAppMenuPropertiesDelegate(this,
110 mIntentDataProvider
.getMenuTitles());
112 new AppMenuHandler(this, mAppMenuPropertiesDelegate
, R
.menu
.custom_tabs_menu
);
113 mToolbarHelper
= new ToolbarHelper(this, controlContainer
,
114 mAppMenuHandler
, mAppMenuPropertiesDelegate
,
115 getCompositorViewHolder().getInvalidator());
116 mToolbarHelper
.setThemeColor(mIntentDataProvider
.getToolbarColor());
117 setStatusBarColor(mIntentDataProvider
.getToolbarColor());
118 if (mIntentDataProvider
.shouldShowActionButton()) {
119 mToolbarHelper
.addCustomActionButton(mIntentDataProvider
.getActionButtonIcon(),
120 new OnClickListener() {
122 public void onClick(View v
) {
123 mIntentDataProvider
.sendButtonPendingIntentWithUrl(
124 getApplicationContext(), mTab
.getUrl());
128 mAppMenuHandler
.addObserver(new AppMenuObserver() {
130 public void onMenuVisibilityChanged(boolean isVisible
) {
132 mAppMenuPropertiesDelegate
.onMenuDismissed();
139 public void finishNativeInitialization() {
140 String url
= IntentHandler
.getUrlFromIntent(getIntent());
141 mSessionId
= mIntentDataProvider
.getSessionId();
142 mTab
= new CustomTab(this, getWindowAndroid(), mSessionId
, url
, Tab
.INVALID_TAB_ID
);
143 getTabModelSelector().setTab(mTab
);
145 ToolbarControlContainer controlContainer
= (ToolbarControlContainer
) findViewById(
146 R
.id
.control_container
);
147 LayoutManagerDocument layoutDriver
= new LayoutManagerDocument(getCompositorViewHolder());
148 initializeCompositorContent(layoutDriver
, findViewById(R
.id
.url_bar
),
149 (ViewGroup
) findViewById(android
.R
.id
.content
), controlContainer
);
150 mFindToolbarManager
= new FindToolbarManager(this, getTabModelSelector(),
151 mToolbarHelper
.getContextualMenuBar().getCustomSelectionActionModeCallback());
152 controlContainer
.setFindToolbarManager(mFindToolbarManager
);
153 mToolbarHelper
.initializeControls(
154 mFindToolbarManager
, null, layoutDriver
, null, null, null,
155 new OnClickListener() {
157 public void onClick(View v
) {
158 CustomTabActivity
.this.finish();
162 mTab
.setFullscreenManager(getFullscreenManager());
163 mTab
.loadUrl(new LoadUrlParams(url
));
164 mCustomTabContentHandler
= new CustomTabContentHandler() {
166 public void loadUrl(LoadUrlParams params
) {
167 mTab
.loadUrl(params
);
171 public long getSessionId() {
175 super.finishNativeInitialization();
179 public void onStartWithNative() {
180 super.onStartWithNative();
181 setActiveContentHandler(mCustomTabContentHandler
);
185 public void onStopWithNative() {
186 super.onStopWithNative();
187 setActiveContentHandler(null);
191 protected void onDeferredStartup() {
192 super.onDeferredStartup();
193 mToolbarHelper
.onDeferredStartup();
197 public boolean hasDoneFirstDraw() {
198 return mToolbarHelper
.hasDoneFirstDraw();
202 * Calculate the proper color for status bar and update it. Only works on L and future versions.
204 private void setStatusBarColor(int color
) {
205 // If the client did not specify the toolbar color, we do not change the status bar color.
206 if (color
== getResources().getColor(R
.color
.default_primary_color
)) return;
208 ApiCompatibilityUtils
.setStatusBarColor(getWindow(),
209 BrandColorUtils
.computeStatusBarColor(color
));
213 public SingleTabModelSelector
getTabModelSelector() {
214 return (SingleTabModelSelector
) super.getTabModelSelector();
218 protected int getControlContainerLayoutId() {
219 return R
.layout
.custom_tabs_control_container
;
223 protected int getControlContainerHeightResource() {
224 return R
.dimen
.custom_tabs_control_container_height
;
228 public String
getPackageName() {
229 if (mShouldOverridePackage
) return mIntentDataProvider
.getClientPackageName();
230 return super.getPackageName();
234 public void finish() {
236 if (mIntentDataProvider
.shouldAnimateOnFinish()) {
237 mShouldOverridePackage
= true;
238 overridePendingTransition(mIntentDataProvider
.getAnimationEnterRes(),
239 mIntentDataProvider
.getAnimationExitRes());
240 mShouldOverridePackage
= false;
245 protected boolean handleBackPressed() {
246 if (mTab
== null) return false;
247 if (mTab
.canGoBack()) {
256 public boolean shouldShowAppMenu() {
257 return mTab
!= null && mToolbarHelper
.isInitialized();
261 public boolean onOptionsItemSelected(MenuItem item
) {
262 int menuIndex
= mAppMenuPropertiesDelegate
.getIndexOfMenuItem(item
);
263 if (menuIndex
>= 0) {
264 mIntentDataProvider
.clickMenuItemWithUrl(getApplicationContext(), menuIndex
,
265 getTabModelSelector().getCurrentTab().getUrl());
268 return super.onOptionsItemSelected(item
);
272 public boolean onMenuOrKeyboardAction(int id
, boolean fromMenu
) {
273 if (id
== R
.id
.show_menu
) {
274 if (shouldShowAppMenu()) {
275 mAppMenuHandler
.showAppMenu(mToolbarHelper
.getMenuAnchor(), true, false);
278 } else if (id
== R
.id
.open_in_chrome_id
) {
279 String url
= getTabModelSelector().getCurrentTab().getUrl();
280 Intent chromeIntent
= new Intent(Intent
.ACTION_VIEW
, Uri
.parse(url
));
281 chromeIntent
.setPackage(getApplicationContext().getPackageName());
282 chromeIntent
.setFlags(Intent
.FLAG_ACTIVITY_NEW_TASK
);
283 startActivity(chromeIntent
);
285 } else if (id
== R
.id
.find_in_page_id
) {
286 mFindToolbarManager
.showToolbar();
289 return super.onMenuOrKeyboardAction(id
, fromMenu
);
293 * @return The {@link AppMenuPropertiesDelegate} associated with this activity. For test
297 CustomTabAppMenuPropertiesDelegate
getAppMenuPropertiesDelegate() {
298 return mAppMenuPropertiesDelegate
;
303 public AppMenuHandler
getAppMenuHandler() {
304 return mAppMenuHandler
;
308 * @return The {@link CustomTabIntentDataProvider} for this {@link CustomTabActivity}. For test
312 CustomTabIntentDataProvider
getIntentDataProvider() {
313 return mIntentDataProvider
;