зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1352997 - Part 5 - Implement common behaviour for custom tabs/web apps and switch over the former. r=sebastian,walkingice
This implements the common behaviour for restoring the correct tab when switching to/from custom tab and web app activities. Unlike our normal UI, those activities are basically single tab activities, that is each activity is linked to a certain Gecko tab, with no facilities (bugs aside) for the user to directly load/select a different tab within that activity. Therefore, here we basically update the selected tab only when the activity is starting up and initially creating its new (or, especially once tab type switching will be implemented, taking over an existing) content tab. When subsequently restoring, we then check whether the tab is still available. If it is, we select it, if not, we fall back to opening a new tab based on the available intent data. This also means that we no longer have to finish() the activity on closing so the activity state (finished) matches the tab (closed), which means that we no longer have to prematurely kill Gecko as a side effect of that. MozReview-Commit-ID: KjFz1qrqWLy --HG-- extra : rebase_source : 188fd2275083ddb982af806d4660c02caab85bee
This commit is contained in:
Родитель
6dcea3ee36
Коммит
a31794fbba
|
@ -1710,10 +1710,20 @@ public abstract class GeckoApp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Tabs.getInstance().loadUrlWithIntentExtras(url, intent, flags);
|
final Tab newTab = Tabs.getInstance().loadUrlWithIntentExtras(url, intent, flags);
|
||||||
|
if (ThreadUtils.isOnUiThread()) {
|
||||||
|
onTabOpenFromIntent(newTab);
|
||||||
|
} else {
|
||||||
|
ThreadUtils.postToUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
onTabOpenFromIntent(newTab);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getIntentURI(SafeIntent intent) {
|
protected String getIntentURI(SafeIntent intent) {
|
||||||
final String passedUri;
|
final String passedUri;
|
||||||
final String uri = getURIFromIntent(intent);
|
final String uri = getURIFromIntent(intent);
|
||||||
|
|
||||||
|
@ -1853,6 +1863,10 @@ public abstract class GeckoApp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void onTabOpenFromIntent(Tab tab) { }
|
||||||
|
|
||||||
|
protected void onTabSelectFromIntent(Tab tab) { }
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||||
@Override
|
@Override
|
||||||
public void onGlobalLayout() {
|
public void onGlobalLayout() {
|
||||||
|
@ -2320,14 +2334,32 @@ public abstract class GeckoApp
|
||||||
recordStartupActionTelemetry(passedUri, action);
|
recordStartupActionTelemetry(passedUri, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether an intent with tab switch extras refers to a tab that
|
||||||
|
* is actually existing at the moment.
|
||||||
|
*
|
||||||
|
* @param intent The intent to be checked.
|
||||||
|
* @return True if the tab specified in the intent is existing in our Tabs list.
|
||||||
|
*/
|
||||||
protected boolean hasGeckoTab(SafeIntent intent) {
|
protected boolean hasGeckoTab(SafeIntent intent) {
|
||||||
final int tabId = intent.getIntExtra(Tabs.INTENT_EXTRA_TAB_ID, INVALID_TAB_ID);
|
final int tabId = intent.getIntExtra(Tabs.INTENT_EXTRA_TAB_ID, INVALID_TAB_ID);
|
||||||
return Tabs.getInstance().getTab(tabId) != null;
|
final String intentSessionUUID = intent.getStringExtra(Tabs.INTENT_EXTRA_SESSION_UUID);
|
||||||
|
final Tab tabToCheck = Tabs.getInstance().getTab(tabId);
|
||||||
|
|
||||||
|
// We only care about comparing session UUIDs if one was specified in the intent.
|
||||||
|
// Otherwise, we just try matching the tab ID with one of our open tabs.
|
||||||
|
return tabToCheck != null && (!intent.hasExtra(Tabs.INTENT_EXTRA_SESSION_UUID) ||
|
||||||
|
GeckoApplication.getSessionUUID().equals(intentSessionUUID));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void handleSelectTabIntent(SafeIntent intent) {
|
protected void handleSelectTabIntent(SafeIntent intent) {
|
||||||
final int tabId = intent.getIntExtra(Tabs.INTENT_EXTRA_TAB_ID, INVALID_TAB_ID);
|
final int tabId = intent.getIntExtra(Tabs.INTENT_EXTRA_TAB_ID, INVALID_TAB_ID);
|
||||||
Tabs.getInstance().selectTab(tabId);
|
final Tab selectedTab = Tabs.getInstance().selectTab(tabId);
|
||||||
|
// If the tab selection has been redirected to a different activity,
|
||||||
|
// the selectedTab within Tabs will not have been updated yet.
|
||||||
|
if (selectedTab == Tabs.getInstance().getSelectedTab()) {
|
||||||
|
onTabSelectFromIntent(selectedTab);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.gecko;
|
||||||
|
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.mozilla.gecko.mozglue.SafeIntent;
|
||||||
|
|
||||||
|
import static org.mozilla.gecko.Tabs.INTENT_EXTRA_SESSION_UUID;
|
||||||
|
import static org.mozilla.gecko.Tabs.INTENT_EXTRA_TAB_ID;
|
||||||
|
import static org.mozilla.gecko.Tabs.INVALID_TAB_ID;
|
||||||
|
|
||||||
|
public abstract class SingleTabActivity extends GeckoApp {
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
final Intent externalIntent = getIntent();
|
||||||
|
// We need the current activity to already be up-to-date before
|
||||||
|
// calling into the superclass.
|
||||||
|
GeckoActivityMonitor.getInstance().setCurrentActivity(this);
|
||||||
|
|
||||||
|
decideTabAction(new SafeIntent(externalIntent), savedInstanceState);
|
||||||
|
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
// GeckoApp's default behaviour is to reset the intent if we've got any
|
||||||
|
// savedInstanceState, which we don't want here.
|
||||||
|
setIntent(externalIntent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onNewIntent(Intent externalIntent) {
|
||||||
|
final SafeIntent intent = new SafeIntent(externalIntent);
|
||||||
|
// We need the current activity to already be up-to-date before
|
||||||
|
// calling into the superclass.
|
||||||
|
GeckoActivityMonitor.getInstance().setCurrentActivity(this);
|
||||||
|
|
||||||
|
if (decideTabAction(intent, null)) {
|
||||||
|
// GeckoApp will handle tab selection.
|
||||||
|
super.onNewIntent(intent.getUnsafe());
|
||||||
|
} else {
|
||||||
|
// We're not calling the superclass in this code path, so we'll
|
||||||
|
// have to notify the activity monitor ourselves.
|
||||||
|
GeckoActivityMonitor.getInstance().onActivityNewIntent(this);
|
||||||
|
loadTabFromIntent(intent);
|
||||||
|
}
|
||||||
|
// Again, unlike GeckoApp's default behaviour we want to keep the intent around
|
||||||
|
// because we might still require its data (e.g. to get custom tab customisations).
|
||||||
|
setIntent(intent.getUnsafe());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean saveSelectedStartupTab() {
|
||||||
|
// We ignore the tab selection made by session restoring in order to display our own tab,
|
||||||
|
// so we should save that tab's ID in case the user starts up our normal browsing UI later
|
||||||
|
// during the session.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void restoreLastSelectedTab() {
|
||||||
|
if (!mInitialized) {
|
||||||
|
// During startup from onCreate(), initialize() will handle selecting the startup tab.
|
||||||
|
// If this here is called afterwards, it's a no-op anyway. If for some reason
|
||||||
|
// (e.g. debugging) initialize() takes longer than usual and hasn't finished by the time
|
||||||
|
// onResume() runs and calls us, we just exit early so as not to interfere.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Tabs tabs = Tabs.getInstance();
|
||||||
|
final Tab tabToSelect = tabs.getTab(mLastSelectedTabId);
|
||||||
|
|
||||||
|
// If the tab we've stored is still existing and valid select it...
|
||||||
|
if (tabToSelect != null && GeckoApplication.getSessionUUID().equals(mLastSessionUUID) &&
|
||||||
|
tabs.currentActivityMatchesTab(tabToSelect)) {
|
||||||
|
tabs.selectTab(mLastSelectedTabId);
|
||||||
|
} else {
|
||||||
|
// ... otherwise fall back to the intent data and open a new tab.
|
||||||
|
loadTabFromIntent(new SafeIntent(getIntent()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadTabFromIntent(final SafeIntent intent) {
|
||||||
|
final int flags = getNewTabFlags();
|
||||||
|
loadStartupTab(getIntentURI(intent), intent, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if we're going to select an existing tab, false if we want to load a new tab.
|
||||||
|
*/
|
||||||
|
private boolean decideTabAction(@NonNull final SafeIntent intent,
|
||||||
|
@Nullable final Bundle savedInstanceState) {
|
||||||
|
final Tabs tabs = Tabs.getInstance();
|
||||||
|
|
||||||
|
if (hasGeckoTab(intent)) {
|
||||||
|
final Tab tabToSelect = tabs.getTab(intent.getIntExtra(INTENT_EXTRA_TAB_ID, INVALID_TAB_ID));
|
||||||
|
if (tabs.currentActivityMatchesTab(tabToSelect)) {
|
||||||
|
// Nothing further to do here, GeckoApp will select the correct
|
||||||
|
// tab from the intent.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// The intent doesn't refer to a valid tab, so don't pass that data on.
|
||||||
|
intent.getUnsafe().removeExtra(INTENT_EXTRA_TAB_ID);
|
||||||
|
intent.getUnsafe().removeExtra(INTENT_EXTRA_SESSION_UUID);
|
||||||
|
// The tab data in the intent can become stale if we've been killed, or have
|
||||||
|
// closed the tab/changed its type since the original intent.
|
||||||
|
// We therefore attempt to fall back to the last selected tab. In onNewIntent,
|
||||||
|
// we can directly use the stored data, otherwise we'll look for it in the
|
||||||
|
// savedInstanceState.
|
||||||
|
final int lastSelectedTabId;
|
||||||
|
final String lastSessionUUID;
|
||||||
|
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
lastSelectedTabId = savedInstanceState.getInt(LAST_SELECTED_TAB);
|
||||||
|
lastSessionUUID = savedInstanceState.getString(LAST_SESSION_UUID);
|
||||||
|
} else {
|
||||||
|
lastSelectedTabId = mLastSelectedTabId;
|
||||||
|
lastSessionUUID = mLastSessionUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Tab tabToSelect = tabs.getTab(lastSelectedTabId);
|
||||||
|
if (tabToSelect != null && GeckoApplication.getSessionUUID().equals(lastSessionUUID) &&
|
||||||
|
tabs.currentActivityMatchesTab(tabToSelect)) {
|
||||||
|
intent.getUnsafe().putExtra(INTENT_EXTRA_TAB_ID, lastSelectedTabId);
|
||||||
|
intent.getUnsafe().putExtra(INTENT_EXTRA_SESSION_UUID, lastSessionUUID);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we end up here, this means that there's no suitable tab we can take over.
|
||||||
|
// Instead, we'll just open a new tab from the data specified in the intent.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDone() {
|
||||||
|
// Our startup logic should be robust enough to cope with it's tab having been closed even
|
||||||
|
// though the activity might survive, so we don't have to call finish() just to make sure
|
||||||
|
// that a new tab is opened in that case. This also has the advantage that we'll remain in
|
||||||
|
// memory as long as the low-memory killer permits, so we can potentially avoid a costly
|
||||||
|
// re-startup of Gecko if the user returns to us soon.
|
||||||
|
moveTaskToBack(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For us here, mLastSelectedTabId/Hash will hold the tab that will be selected when the
|
||||||
|
* activity is resumed/recreated, unless
|
||||||
|
* - it has been explicitly overridden through an intent
|
||||||
|
* - the tab cannot be found, in which case the URI passed as intent data will instead be
|
||||||
|
* opened in a new tab.
|
||||||
|
* Therefore, we only update the stored tab data from those two locations.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an intent or onResume() has caused us to load and select a new tab.
|
||||||
|
*
|
||||||
|
* @param tab The new tab that has been opened and selected.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onTabOpenFromIntent(Tab tab) {
|
||||||
|
mLastSelectedTabId = tab.getId();
|
||||||
|
mLastSessionUUID = GeckoApplication.getSessionUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an intent has caused us to select an already existing tab.
|
||||||
|
*
|
||||||
|
* @param tab The already existing tab that has been selected for this activity.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onTabSelectFromIntent(Tab tab) {
|
||||||
|
mLastSelectedTabId = tab.getId();
|
||||||
|
mLastSessionUUID = GeckoApplication.getSessionUUID();
|
||||||
|
}
|
||||||
|
}
|
|
@ -64,6 +64,7 @@ public class Tabs implements BundleEventListener {
|
||||||
private static final String LOGTAG = "GeckoTabs";
|
private static final String LOGTAG = "GeckoTabs";
|
||||||
|
|
||||||
public static final String INTENT_EXTRA_TAB_ID = "TabId";
|
public static final String INTENT_EXTRA_TAB_ID = "TabId";
|
||||||
|
public static final String INTENT_EXTRA_SESSION_UUID = "SessionUUID";
|
||||||
private static final String PRIVATE_TAB_INTENT_EXTRA = "private_tab";
|
private static final String PRIVATE_TAB_INTENT_EXTRA = "private_tab";
|
||||||
|
|
||||||
// mOrder and mTabs are always of the same cardinality, and contain the same values.
|
// mOrder and mTabs are always of the same cardinality, and contain the same values.
|
||||||
|
@ -353,7 +354,7 @@ public class Tabs implements BundleEventListener {
|
||||||
/**
|
/**
|
||||||
* Check whether the currently active activity matches the tab type of the passed tab.
|
* Check whether the currently active activity matches the tab type of the passed tab.
|
||||||
*/
|
*/
|
||||||
private boolean currentActivityMatchesTab(Tab tab) {
|
public boolean currentActivityMatchesTab(Tab tab) {
|
||||||
final Activity currentActivity = GeckoActivityMonitor.getInstance().getCurrentActivity();
|
final Activity currentActivity = GeckoActivityMonitor.getInstance().getCurrentActivity();
|
||||||
|
|
||||||
if (currentActivity == null) {
|
if (currentActivity == null) {
|
||||||
|
@ -394,6 +395,7 @@ public class Tabs implements BundleEventListener {
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
intent.putExtra(BrowserContract.SKIP_TAB_QUEUE_FLAG, true);
|
intent.putExtra(BrowserContract.SKIP_TAB_QUEUE_FLAG, true);
|
||||||
intent.putExtra(INTENT_EXTRA_TAB_ID, tab.getId());
|
intent.putExtra(INTENT_EXTRA_TAB_ID, tab.getId());
|
||||||
|
intent.putExtra(INTENT_EXTRA_SESSION_UUID, GeckoApplication.getSessionUUID());
|
||||||
mAppContext.startActivity(intent);
|
mAppContext.startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,8 +32,8 @@ import android.view.View;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
import org.mozilla.gecko.EventDispatcher;
|
import org.mozilla.gecko.EventDispatcher;
|
||||||
import org.mozilla.gecko.GeckoApp;
|
|
||||||
import org.mozilla.gecko.R;
|
import org.mozilla.gecko.R;
|
||||||
|
import org.mozilla.gecko.SingleTabActivity;
|
||||||
import org.mozilla.gecko.SnackbarBuilder;
|
import org.mozilla.gecko.SnackbarBuilder;
|
||||||
import org.mozilla.gecko.Tab;
|
import org.mozilla.gecko.Tab;
|
||||||
import org.mozilla.gecko.Tabs;
|
import org.mozilla.gecko.Tabs;
|
||||||
|
@ -55,9 +55,9 @@ import java.util.List;
|
||||||
|
|
||||||
import static org.mozilla.gecko.Tabs.TabEvents;
|
import static org.mozilla.gecko.Tabs.TabEvents;
|
||||||
|
|
||||||
public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedListener {
|
public class CustomTabsActivity extends SingleTabActivity implements Tabs.OnTabsChangedListener {
|
||||||
|
|
||||||
private static final String LOGTAG = "CustomTabsActivity";
|
private static final String LOGTAG = "CustomTabsActivity";
|
||||||
private static final String SAVED_START_INTENT = "saved_intent_which_started_this_activity";
|
|
||||||
|
|
||||||
private final SparseArrayCompat<PendingIntent> menuItemsIntent = new SparseArrayCompat<>();
|
private final SparseArrayCompat<PendingIntent> menuItemsIntent = new SparseArrayCompat<>();
|
||||||
private GeckoPopupMenu popupMenu;
|
private GeckoPopupMenu popupMenu;
|
||||||
|
@ -67,28 +67,13 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
// A state to indicate whether this activity is finishing with customize animation
|
// A state to indicate whether this activity is finishing with customize animation
|
||||||
private boolean usingCustomAnimation = false;
|
private boolean usingCustomAnimation = false;
|
||||||
|
|
||||||
// Bug 1351605 - getIntent() not always returns the intent which started this activity.
|
|
||||||
// Therefore we make a copy in case of this Activity is re-created.
|
|
||||||
private SafeIntent startIntent;
|
|
||||||
|
|
||||||
private MenuItem menuItemControl;
|
private MenuItem menuItemControl;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
if (savedInstanceState != null) {
|
final SafeIntent intent = new SafeIntent(getIntent());
|
||||||
final Intent restoredIntent = savedInstanceState.getParcelable(SAVED_START_INTENT);
|
|
||||||
startIntent = new SafeIntent(restoredIntent);
|
|
||||||
} else {
|
|
||||||
startIntent = new SafeIntent(getIntent());
|
|
||||||
final String host = getReferrerHost();
|
|
||||||
recordCustomTabUsage(host);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mIsRestoringActivity || !hasGeckoTab(startIntent)) {
|
|
||||||
sendTelemetry();
|
|
||||||
}
|
|
||||||
|
|
||||||
setThemeFromToolbarColor();
|
setThemeFromToolbarColor();
|
||||||
|
|
||||||
|
@ -101,14 +86,36 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
bindNavigationCallback(toolbar);
|
bindNavigationCallback(toolbar);
|
||||||
|
|
||||||
actionBarPresenter = new ActionBarPresenter(actionBar);
|
actionBarPresenter = new ActionBarPresenter(actionBar);
|
||||||
actionBarPresenter.displayUrlOnly(startIntent.getDataString());
|
actionBarPresenter.displayUrlOnly(intent.getDataString());
|
||||||
actionBarPresenter.setBackgroundColor(IntentUtil.getToolbarColor(startIntent), getWindow());
|
actionBarPresenter.setBackgroundColor(IntentUtil.getToolbarColor(intent), getWindow());
|
||||||
actionBarPresenter.setTextLongClickListener(new UrlCopyListener());
|
actionBarPresenter.setTextLongClickListener(new UrlCopyListener());
|
||||||
|
|
||||||
Tabs.registerOnTabsChangedListener(this);
|
Tabs.registerOnTabsChangedListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onTabOpenFromIntent(Tab tab) {
|
||||||
|
super.onTabOpenFromIntent(tab);
|
||||||
|
|
||||||
|
final String host = getReferrerHost();
|
||||||
|
recordCustomTabUsage(host);
|
||||||
|
sendTelemetry();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onTabSelectFromIntent(Tab tab) {
|
||||||
|
super.onTabSelectFromIntent(tab);
|
||||||
|
|
||||||
|
// We already listen for SELECTED events, but if the activity has been destroyed and
|
||||||
|
// subsequently recreated without a different tab having been selected in Gecko in the
|
||||||
|
// meantime, our startup won't trigger a SELECTED event because the selected tab in Gecko
|
||||||
|
// doesn't actually change.
|
||||||
|
actionBarPresenter.update(tab);
|
||||||
|
}
|
||||||
|
|
||||||
private void sendTelemetry() {
|
private void sendTelemetry() {
|
||||||
|
final SafeIntent startIntent = new SafeIntent(getIntent());
|
||||||
|
|
||||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "customtab");
|
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "customtab");
|
||||||
if (IntentUtil.hasToolbarColor(startIntent)) {
|
if (IntentUtil.hasToolbarColor(startIntent)) {
|
||||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "customtab-hasToolbarColor");
|
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "customtab-hasToolbarColor");
|
||||||
|
@ -122,8 +129,6 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
if (IntentUtil.hasShareItem(startIntent)) {
|
if (IntentUtil.hasShareItem(startIntent)) {
|
||||||
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "customtab-hasShareItem");
|
Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "customtab-hasShareItem");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void recordCustomTabUsage(final String host) {
|
private void recordCustomTabUsage(final String host) {
|
||||||
|
@ -138,7 +143,7 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setThemeFromToolbarColor() {
|
private void setThemeFromToolbarColor() {
|
||||||
final int color = ColorUtil.getReadableTextColor(IntentUtil.getToolbarColor(startIntent));
|
final int color = ColorUtil.getReadableTextColor(IntentUtil.getToolbarColor(new SafeIntent(getIntent())));
|
||||||
@StyleRes final int styleRes = (color == Color.BLACK)
|
@StyleRes final int styleRes = (color == Color.BLACK)
|
||||||
? R.style.GeckoCustomTabs_Light
|
? R.style.GeckoCustomTabs_Light
|
||||||
: R.style.GeckoCustomTabs;
|
: R.style.GeckoCustomTabs;
|
||||||
|
@ -153,7 +158,7 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
public String getPackageName() {
|
public String getPackageName() {
|
||||||
if (usingCustomAnimation) {
|
if (usingCustomAnimation) {
|
||||||
// Use its package name to retrieve animation resource
|
// Use its package name to retrieve animation resource
|
||||||
return IntentUtil.getAnimationPackageName(startIntent);
|
return IntentUtil.getAnimationPackageName(new SafeIntent(getIntent()));
|
||||||
} else {
|
} else {
|
||||||
return super.getPackageName();
|
return super.getPackageName();
|
||||||
}
|
}
|
||||||
|
@ -163,11 +168,12 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
public void finish() {
|
public void finish() {
|
||||||
super.finish();
|
super.finish();
|
||||||
|
|
||||||
|
final SafeIntent intent = new SafeIntent(getIntent());
|
||||||
// When 3rd party app launch this Activity, it could also specify custom exit-animation.
|
// When 3rd party app launch this Activity, it could also specify custom exit-animation.
|
||||||
if (IntentUtil.hasExitAnimation(startIntent)) {
|
if (IntentUtil.hasExitAnimation(intent)) {
|
||||||
usingCustomAnimation = true;
|
usingCustomAnimation = true;
|
||||||
overridePendingTransition(IntentUtil.getEnterAnimationRes(startIntent),
|
overridePendingTransition(IntentUtil.getEnterAnimationRes(intent),
|
||||||
IntentUtil.getExitAnimationRes(startIntent));
|
IntentUtil.getExitAnimationRes(intent));
|
||||||
usingCustomAnimation = false;
|
usingCustomAnimation = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -193,11 +199,6 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
return doorhangerOverlay;
|
return doorhangerOverlay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onDone() {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTabChanged(Tab tab, TabEvents msg, String data) {
|
public void onTabChanged(Tab tab, TabEvents msg, String data) {
|
||||||
if (!Tabs.getInstance().isSelectedTab(tab) ||
|
if (!Tabs.getInstance().isSelectedTab(tab) ||
|
||||||
|
@ -227,12 +228,6 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
updateMenuItemForward();
|
updateMenuItemForward();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onSaveInstanceState(Bundle outState) {
|
|
||||||
super.onSaveInstanceState(outState);
|
|
||||||
outState.putParcelable(SAVED_START_INTENT, startIntent.getUnsafe());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
@ -253,10 +248,11 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
public boolean onCreatePanelMenu(final int id, final Menu menu) {
|
public boolean onCreatePanelMenu(final int id, final Menu menu) {
|
||||||
|
|
||||||
// if 3rd-party app asks to add an action button
|
// if 3rd-party app asks to add an action button
|
||||||
if (IntentUtil.hasActionButton(startIntent)) {
|
SafeIntent intent = new SafeIntent(getIntent());
|
||||||
final Bitmap bitmap = IntentUtil.getActionButtonIcon(startIntent);
|
if (IntentUtil.hasActionButton(intent)) {
|
||||||
|
final Bitmap bitmap = IntentUtil.getActionButtonIcon(intent);
|
||||||
final Drawable icon = new BitmapDrawable(getResources(), bitmap);
|
final Drawable icon = new BitmapDrawable(getResources(), bitmap);
|
||||||
final boolean shouldTint = IntentUtil.isActionButtonTinted(startIntent);
|
final boolean shouldTint = IntentUtil.isActionButtonTinted(intent);
|
||||||
actionBarPresenter.addActionButton(menu, icon, shouldTint)
|
actionBarPresenter.addActionButton(menu, icon, shouldTint)
|
||||||
.setOnClickListener(new View.OnClickListener() {
|
.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -349,10 +345,10 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
onDone();
|
||||||
final Tabs tabs = Tabs.getInstance();
|
final Tabs tabs = Tabs.getInstance();
|
||||||
final Tab tab = tabs.getSelectedTab();
|
final Tab tab = tabs.getSelectedTab();
|
||||||
tabs.closeTab(tab);
|
tabs.closeTab(tab);
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -378,6 +374,7 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
private GeckoPopupMenu createCustomPopupMenu() {
|
private GeckoPopupMenu createCustomPopupMenu() {
|
||||||
final GeckoPopupMenu popupMenu = new GeckoPopupMenu(this);
|
final GeckoPopupMenu popupMenu = new GeckoPopupMenu(this);
|
||||||
final GeckoMenu geckoMenu = popupMenu.getMenu();
|
final GeckoMenu geckoMenu = popupMenu.getMenu();
|
||||||
|
final SafeIntent intent = new SafeIntent(getIntent());
|
||||||
|
|
||||||
// pass to to Activity.onMenuItemClick for consistency.
|
// pass to to Activity.onMenuItemClick for consistency.
|
||||||
popupMenu.setOnMenuItemClickListener(new GeckoPopupMenu.OnMenuItemClickListener() {
|
popupMenu.setOnMenuItemClickListener(new GeckoPopupMenu.OnMenuItemClickListener() {
|
||||||
|
@ -388,8 +385,8 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
});
|
});
|
||||||
|
|
||||||
// to add custom menu items
|
// to add custom menu items
|
||||||
final List<String> titles = IntentUtil.getMenuItemsTitle(startIntent);
|
final List<String> titles = IntentUtil.getMenuItemsTitle(intent);
|
||||||
final List<PendingIntent> intents = IntentUtil.getMenuItemsPendingIntent(startIntent);
|
final List<PendingIntent> intents = IntentUtil.getMenuItemsPendingIntent(intent);
|
||||||
menuItemsIntent.clear();
|
menuItemsIntent.clear();
|
||||||
for (int i = 0; i < titles.size(); i++) {
|
for (int i = 0; i < titles.size(); i++) {
|
||||||
final int menuId = Menu.FIRST + i;
|
final int menuId = Menu.FIRST + i;
|
||||||
|
@ -398,7 +395,7 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
}
|
}
|
||||||
|
|
||||||
// to add share menu item, if necessary
|
// to add share menu item, if necessary
|
||||||
if (IntentUtil.hasShareItem(startIntent) && !TextUtils.isEmpty(startIntent.getDataString())) {
|
if (IntentUtil.hasShareItem(intent) && !TextUtils.isEmpty(intent.getDataString())) {
|
||||||
geckoMenu.add(Menu.NONE, R.id.share, Menu.NONE, getString(R.string.share));
|
geckoMenu.add(Menu.NONE, R.id.share, Menu.NONE, getString(R.string.share));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,7 +496,7 @@ public class CustomTabsActivity extends GeckoApp implements Tabs.OnTabsChangedLi
|
||||||
|
|
||||||
private void onActionButtonClicked() {
|
private void onActionButtonClicked() {
|
||||||
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.MENU, "customtab-action-button");
|
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.MENU, "customtab-action-button");
|
||||||
PendingIntent pendingIntent = IntentUtil.getActionButtonPendingIntent(startIntent);
|
PendingIntent pendingIntent = IntentUtil.getActionButtonPendingIntent(new SafeIntent(getIntent()));
|
||||||
performPendingIntent(pendingIntent);
|
performPendingIntent(pendingIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -821,6 +821,7 @@ gbjar.sources += ['java/org/mozilla/gecko/' + x for x in [
|
||||||
'search/SearchEngineManager.java',
|
'search/SearchEngineManager.java',
|
||||||
'SessionParser.java',
|
'SessionParser.java',
|
||||||
'SharedPreferencesHelper.java',
|
'SharedPreferencesHelper.java',
|
||||||
|
'SingleTabActivity.java',
|
||||||
'SiteIdentity.java',
|
'SiteIdentity.java',
|
||||||
'SnackbarBuilder.java',
|
'SnackbarBuilder.java',
|
||||||
'SuggestClient.java',
|
'SuggestClient.java',
|
||||||
|
|
|
@ -64,9 +64,9 @@ public class TestCustomTabsActivity {
|
||||||
@Test
|
@Test
|
||||||
public void testFinishWithoutCustomAnimation() {
|
public void testFinishWithoutCustomAnimation() {
|
||||||
final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
||||||
final SafeIntent i = new SafeIntent(builder.build().intent);
|
final Intent i = builder.build().intent;
|
||||||
|
|
||||||
Whitebox.setInternalState(spyActivity, "startIntent", i);
|
doReturn(i).when(spyActivity).getIntent();
|
||||||
|
|
||||||
spyActivity.finish();
|
spyActivity.finish();
|
||||||
verify(spyActivity, times(0)).overridePendingTransition(anyInt(), anyInt());
|
verify(spyActivity, times(0)).overridePendingTransition(anyInt(), anyInt());
|
||||||
|
@ -79,9 +79,9 @@ public class TestCustomTabsActivity {
|
||||||
public void testFinish() {
|
public void testFinish() {
|
||||||
final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
||||||
builder.setExitAnimations(spyContext, enterRes, exitRes);
|
builder.setExitAnimations(spyContext, enterRes, exitRes);
|
||||||
final SafeIntent i = new SafeIntent(builder.build().intent);
|
final Intent i = builder.build().intent;
|
||||||
|
|
||||||
Whitebox.setInternalState(spyActivity, "startIntent", i);
|
doReturn(i).when(spyActivity).getIntent();
|
||||||
|
|
||||||
spyActivity.finish();
|
spyActivity.finish();
|
||||||
verify(spyActivity, times(1)).overridePendingTransition(eq(enterRes), eq(exitRes));
|
verify(spyActivity, times(1)).overridePendingTransition(eq(enterRes), eq(exitRes));
|
||||||
|
@ -94,10 +94,10 @@ public class TestCustomTabsActivity {
|
||||||
public void testGetPackageName() {
|
public void testGetPackageName() {
|
||||||
final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
|
||||||
builder.setExitAnimations(spyContext, enterRes, exitRes);
|
builder.setExitAnimations(spyContext, enterRes, exitRes);
|
||||||
final SafeIntent i = new SafeIntent(builder.build().intent);
|
final Intent i = builder.build().intent;
|
||||||
|
|
||||||
|
doReturn(i).when(spyActivity).getIntent();
|
||||||
Whitebox.setInternalState(spyActivity, "usingCustomAnimation", true);
|
Whitebox.setInternalState(spyActivity, "usingCustomAnimation", true);
|
||||||
Whitebox.setInternalState(spyActivity, "startIntent", i);
|
|
||||||
|
|
||||||
Assert.assertEquals(THIRD_PARTY_PACKAGE_NAME, spyActivity.getPackageName());
|
Assert.assertEquals(THIRD_PARTY_PACKAGE_NAME, spyActivity.getPackageName());
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче