Commit c0f99a3f authored by Peter Kotwicz's avatar Peter Kotwicz Committed by Commit Bot

Make WebappActivity use TabModelImpl

This CL makes WebappActivity use:
- TabModelImpl
- CustomTabTabPersistencePolicy instead of WebappDirectoryManager

BUG=1032291

Change-Id: I7adc8288105aa161eedbab4ba37724d91c305e07
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1965900
Commit-Queue: Peter Kotwicz <pkotwicz@chromium.org>
Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Reviewed-by: default avatarPeter Conn <peconn@chromium.org>
Cr-Commit-Position: refs/heads/master@{#727021}
parent 675e4df8
......@@ -1634,8 +1634,6 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/tabmodel/EmptyTabModelSelectorObserver.java",
"java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModel.java",
"java/src/org/chromium/chrome/browser/tabmodel/IncognitoTabModelImplCreator.java",
"java/src/org/chromium/chrome/browser/tabmodel/SingleTabModel.java",
"java/src/org/chromium/chrome/browser/tabmodel/SingleTabModelSelector.java",
"java/src/org/chromium/chrome/browser/tabmodel/TabCreatorManager.java",
"java/src/org/chromium/chrome/browser/tabmodel/TabList.java",
"java/src/org/chromium/chrome/browser/tabmodel/TabModel.java",
......
......@@ -4,8 +4,10 @@
package org.chromium.chrome.browser.customtabs;
import android.util.Pair;
import android.view.KeyEvent;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import org.chromium.chrome.R;
......@@ -13,12 +15,17 @@ import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.KeyboardShortcuts;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityNavigationController;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabFactory;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabProvider;
import org.chromium.chrome.browser.customtabs.content.TabCreationMode;
import org.chromium.chrome.browser.customtabs.dependency_injection.BaseCustomTabActivityComponent;
import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarCoordinator;
import org.chromium.chrome.browser.dependency_injection.ChromeActivityComponent;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabState;
import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
import org.chromium.chrome.browser.ui.RootUiCoordinator;
/**
......@@ -33,6 +40,7 @@ public abstract class BaseCustomTabActivity<C extends ChromeActivityComponent>
protected CustomTabActivityNavigationController mNavigationController;
protected CustomTabActivityTabProvider mTabProvider;
protected CustomTabStatusBarColorProvider mStatusBarColorProvider;
protected CustomTabActivityTabFactory mTabFactory;
// This is to give the right package name while using the client's resources during an
// overridePendingTransition call.
......@@ -60,11 +68,39 @@ public abstract class BaseCustomTabActivity<C extends ChromeActivityComponent>
mNavigationController = component.resolveNavigationController();
mTabProvider = component.resolveTabProvider();
mStatusBarColorProvider = component.resolveCustomTabStatusBarColorProvider();
mTabFactory = component.resolveTabFactory();
component.resolveCompositorContentInitializer();
component.resolveTaskDescriptionHelper();
}
@Override
protected TabModelSelector createTabModelSelector() {
return mTabFactory.createTabModelSelector();
}
@Override
protected Pair<ChromeTabCreator, ChromeTabCreator> createTabCreators() {
return mTabFactory.createTabCreators();
}
@Override
public void initializeCompositor() {
super.initializeCompositor();
getTabModelSelector().onNativeLibraryReady(getTabContentManager());
}
@Override
public TabModelSelectorImpl getTabModelSelector() {
return (TabModelSelectorImpl) super.getTabModelSelector();
}
@Override
@Nullable
public Tab getActivityTab() {
return mTabProvider.getTab();
}
@Override
protected int getControlContainerLayoutId() {
return R.layout.custom_tabs_control_container;
......
......@@ -18,7 +18,6 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Browser;
import android.util.Pair;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
......@@ -38,7 +37,6 @@ import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantFacade;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider.CustomTabsUiType;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabController;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabFactory;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabProvider;
import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandler;
import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandler.IntentIgnoringCriterion;
......@@ -58,9 +56,6 @@ import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
import org.chromium.chrome.browser.page_info.PageInfoController;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabImpl;
import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate;
import org.chromium.chrome.browser.usage_stats.UsageStatsService;
import org.chromium.chrome.browser.util.IntentUtils;
......@@ -74,7 +69,6 @@ public class CustomTabActivity extends BaseCustomTabActivity<CustomTabActivityCo
private CustomTabIntentDataProvider mIntentDataProvider;
private CustomTabsSessionToken mSession;
private CustomTabActivityTabController mTabController;
private CustomTabActivityTabFactory mTabFactory;
private CustomTabIntentHandler mCustomTabIntentHandler;
private final CustomTabsConnection mConnection = CustomTabsConnection.getInstance();
......@@ -189,16 +183,6 @@ public class CustomTabActivity extends BaseCustomTabActivity<CustomTabActivityCo
getComponent().resolveBottomBarDelegate().showBottomBarIfNecessary();
}
@Override
protected TabModelSelector createTabModelSelector() {
return mTabFactory.createTabModelSelector();
}
@Override
protected Pair<ChromeTabCreator, ChromeTabCreator> createTabCreators() {
return mTabFactory.createTabCreators();
}
@Override
protected NightModeStateProvider createNightModeStateProvider() {
// This is called before Dagger component is created, so using getInstance() directly.
......@@ -265,29 +249,12 @@ public class CustomTabActivity extends BaseCustomTabActivity<CustomTabActivityCo
}
}
@Override
public void initializeCompositor() {
super.initializeCompositor();
getTabModelSelector().onNativeLibraryReady(getTabContentManager());
}
@Override
public void createContextualSearchTab(String searchUrl) {
if (getActivityTab() == null) return;
getActivityTab().loadUrl(new LoadUrlParams(searchUrl));
}
@Override
public TabModelSelectorImpl getTabModelSelector() {
return (TabModelSelectorImpl) super.getTabModelSelector();
}
@Override
@Nullable
public Tab getActivityTab() {
return mTabProvider.getTab();
}
@Override
public AppMenuPropertiesDelegate createAppMenuPropertiesDelegate() {
return new CustomTabAppMenuPropertiesDelegate(this, getActivityTabProvider(),
......@@ -473,7 +440,6 @@ public class CustomTabActivity extends BaseCustomTabActivity<CustomTabActivityCo
onComponentCreated(component);
mTabController = component.resolveTabController();
mTabFactory = component.resolveTabFactory();
component.resolveUmaTracker();
CustomTabActivityClientConnectionKeeper connectionKeeper =
component.resolveConnectionKeeper();
......
......@@ -276,7 +276,8 @@ public class CustomTabTabPersistencePolicy implements TabPersistencePolicy {
* @param activity The activity whose tab IDs are to be collected from.
* @param tabIds Where the tab IDs should be added to.
*/
private static void getAllTabIdsForActivity(CustomTabActivity activity, Set<Integer> tabIds) {
private static void getAllTabIdsForActivity(
BaseCustomTabActivity activity, Set<Integer> tabIds) {
if (activity == null) return;
TabModelSelector selector = activity.getTabModelSelector();
if (selector == null) return;
......@@ -300,8 +301,8 @@ public class CustomTabTabPersistencePolicy implements TabPersistencePolicy {
ThreadUtils.assertOnUiThread();
for (Activity activity : ApplicationStatus.getRunningActivities()) {
if (!(activity instanceof CustomTabActivity)) continue;
getAllTabIdsForActivity((CustomTabActivity) activity, liveTabIds);
if (!(activity instanceof BaseCustomTabActivity)) continue;
getAllTabIdsForActivity((BaseCustomTabActivity) activity, liveTabIds);
liveTaskIds.add(activity.getTaskId());
}
}
......@@ -389,7 +390,8 @@ public class CustomTabTabPersistencePolicy implements TabPersistencePolicy {
try {
int taskId = Integer.parseInt(id);
// Ignore the metadata file if it belongs to a currently live CustomTabActivity.
// Ignore the metadata file if it belongs to a currently live
// BaseCustomTabActivity.
if (liveTaskIds.contains(taskId)) continue;
filesToDelete.add(metadataFile.getName());
......
......@@ -24,6 +24,8 @@ import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
import org.chromium.chrome.browser.util.IntentUtils;
import org.chromium.chrome.browser.webapps.WebappActivity;
import org.chromium.chrome.browser.webapps.WebappTabDelegate;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.ActivityWindowAndroid;
......@@ -42,6 +44,8 @@ public class CustomTabActivityTabFactory {
private final Lazy<ActivityWindowAndroid> mActivityWindowAndroid;
private final Lazy<CustomTabDelegateFactory> mCustomTabDelegateFactory;
private final BrowserServicesIntentDataProvider mIntentDataProvider;
@Nullable
private final StartupTabPreloader mStartupTabPreloader;
@Nullable
......@@ -53,7 +57,7 @@ public class CustomTabActivityTabFactory {
Lazy<ActivityWindowAndroid> activityWindowAndroid,
Lazy<CustomTabDelegateFactory> customTabDelegateFactory,
BrowserServicesIntentDataProvider intentDataProvider,
StartupTabPreloader startupTabPreloader) {
@Nullable StartupTabPreloader startupTabPreloader) {
mActivity = activity;
mPersistencePolicy = persistencePolicy;
mActivityWindowAndroid = activityWindowAndroid;
......@@ -84,6 +88,10 @@ public class CustomTabActivityTabFactory {
}
private ChromeTabCreator createTabCreator(boolean incognito) {
if (mIntentDataProvider.getWebappExtras() != null) {
return new WebappTabDelegate((WebappActivity) mActivity, mActivityWindowAndroid.get(),
mStartupTabPreloader, mCustomTabDelegateFactory::get, incognito);
}
return new ChromeTabCreator(mActivity, mActivityWindowAndroid.get(), mStartupTabPreloader,
mCustomTabDelegateFactory::get, incognito) {
@Override
......
......@@ -9,6 +9,7 @@ import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory;
import org.chromium.chrome.browser.customtabs.CustomTabStatusBarColorProvider;
import org.chromium.chrome.browser.customtabs.CustomTabTaskDescriptionHelper;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityNavigationController;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabFactory;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabProvider;
import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar;
import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarCoordinator;
......@@ -21,6 +22,7 @@ import org.chromium.chrome.browser.webapps.SplashController;
*/
public interface BaseCustomTabActivityComponent extends ChromeActivityComponent {
CustomTabActivityNavigationController resolveNavigationController();
CustomTabActivityTabFactory resolveTabFactory();
CustomTabActivityTabProvider resolveTabProvider();
CustomTabCompositorContentInitializer resolveCompositorContentInitializer();
CustomTabDelegateFactory resolveTabDelegateFactory();
......
......@@ -15,7 +15,6 @@ import org.chromium.chrome.browser.customtabs.CustomTabTabPersistencePolicy;
import org.chromium.chrome.browser.customtabs.CustomTabUmaRecorder;
import org.chromium.chrome.browser.customtabs.ReparentingTaskProvider;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabController;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabFactory;
import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandler;
import org.chromium.chrome.browser.customtabs.dynamicmodule.DynamicModuleCoordinator;
import org.chromium.chrome.browser.customtabs.dynamicmodule.DynamicModuleToolbarController;
......@@ -39,7 +38,6 @@ public interface CustomTabActivityComponent extends BaseCustomTabActivityCompone
CustomTabBottomBarDelegate resolveBottomBarDelegate();
CustomTabActivityTabController resolveTabController();
CustomTabActivityTabFactory resolveTabFactory();
CustomTabActivityLifecycleUmaTracker resolveUmaTracker();
CustomTabIntentHandler resolveIntentHandler();
CustomTabIncognitoManager resolveCustomTabIncognitoManager();
......
// 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.chrome.browser.tabmodel;
import android.app.Activity;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.ObserverList;
import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabImpl;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tab.TabSelectionType;
import java.util.List;
/**
* Simple TabModel that assumes that only one Tab exists.
*/
public class SingleTabModel implements TabModel {
private final Activity mActivity;
private final ObserverList<TabModelObserver> mObservers = new ObserverList<>();
private Tab mTab;
private boolean mIsIncognito;
SingleTabModel(Activity activity, boolean incognito) {
mActivity = activity;
mIsIncognito = incognito;
}
/**
* Sets the Tab that is managed by the SingleTabModel.
* @param tab Tab to manage.
*/
void setTab(Tab tab) {
if (mTab == tab) return;
Tab oldTab = mTab;
mTab = tab;
if (oldTab != null) {
for (TabModelObserver observer : mObservers) {
observer.willCloseTab(oldTab, false);
}
}
if (tab != null) {
assert mTab.isIncognito() == mIsIncognito;
for (TabModelObserver observer : mObservers) {
observer.didAddTab(tab, TabLaunchType.FROM_LINK);
observer.didSelectTab(tab, TabSelectionType.FROM_USER, Tab.INVALID_TAB_ID);
}
int state = ApplicationStatus.getStateForActivity(mActivity);
if (state == ActivityState.CREATED || state == ActivityState.STARTED
|| state == ActivityState.RESUMED) {
mTab.show(TabSelectionType.FROM_USER);
}
}
if (oldTab != null && oldTab.isInitialized()) {
for (TabModelObserver observer : mObservers) {
observer.didCloseTab(oldTab.getId(), oldTab.isIncognito());
}
oldTab.destroy();
}
}
@Override
public Profile getProfile() {
return mTab == null ? null : ((TabImpl) mTab).getProfile();
}
@Override
public boolean isIncognito() {
return mIsIncognito;
}
@Override
public int getCount() {
return mTab == null ? 0 : 1;
}
@Override
public int indexOf(Tab tab) {
if (tab == null) return INVALID_TAB_INDEX;
return mTab != null && mTab.getId() == tab.getId() ? 0 : INVALID_TAB_INDEX;
}
@Override
public int index() {
return mTab != null ? 0 : INVALID_TAB_INDEX;
}
@Override
public boolean closeTab(Tab tab) {
return closeTab(tab, false, false, false);
}
@Override
public boolean closeTab(Tab tab, boolean animate, boolean uponExit, boolean canUndo) {
if (mTab == null || mTab.getId() != tab.getId()) return false;
setTab(null);
return true;
}
@Override
public boolean closeTab(
Tab tab, Tab recommendedNextTab, boolean animate, boolean uponExit, boolean canUndo) {
return closeTab(tab, animate, uponExit, canUndo);
}
@Override
public void closeMultipleTabs(List<Tab> tabs, boolean canUndo) {
if (mTab == null) return;
for (Tab tab : tabs) {
if (tab.getId() == mTab.getId()) {
setTab(null);
return;
}
}
}
@Override
public void closeAllTabs() {
closeAllTabs(true, false);
}
@Override
public void closeAllTabs(boolean allowDelegation, boolean uponExit) {
setTab(null);
}
// Tab retrieval functions.
@Override
public Tab getTabAt(int position) {
return position == 0 ? mTab : null;
}
@Override
public void setIndex(int i, final @TabSelectionType int type) {
assert i == 0;
}
@Override
public boolean isCurrentModel() {
return true;
}
@Override
public void moveTab(int id, int newIndex) {
assert false;
}
@Override
public void destroy() {
if (mTab != null) mTab.destroy();
mTab = null;
}
@Override
public Tab getNextTabIfClosed(int id) {
return null;
}
@Override
public boolean isClosurePending(int tabId) {
return false;
}
@Override
public TabList getComprehensiveModel() {
return this;
}
@Override
public void commitAllTabClosures() {}
@Override
public void commitTabClosure(int tabId) {}
@Override
public void cancelTabClosure(int tabId) {}
@Override
public boolean supportsPendingClosures() {
return false;
}
@Override
public void addTab(Tab tab, int index, @TabLaunchType int type) {
setTab(tab);
}
@Override
public void removeTab(Tab tab) {
mTab = null;
for (TabModelObserver obs : mObservers) obs.tabRemoved(tab);
}
@Override
public void addObserver(TabModelObserver observer) {
mObservers.addObserver(observer);
}
@Override
public void removeObserver(TabModelObserver observer) {
mObservers.removeObserver(observer);
}
@Override
public void openMostRecentlyClosedTab() {}
}
// 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.chrome.browser.tabmodel;
import android.app.Activity;
import org.chromium.chrome.browser.tab.Tab;
/**
* Simple TabModelSelector that assumes that only a single TabModel exists at a time.
*/
public class SingleTabModelSelector extends TabModelSelectorBase {
public SingleTabModelSelector(
Activity activity, TabCreatorManager tabCreatorManager, boolean incognito) {
super(tabCreatorManager, incognito);
initialize(new SingleTabModel(activity, incognito));
TabModelObserver tabModelObserver = new EmptyTabModelObserver() {
@Override
public void didCloseTab(int tabId, boolean incognito) {
// TabModelSelectorImpl handles the equivalent case of closing the last tab in
// TabModelSelectorImpl#requestToShowTab, which we don't have for this
// TabModelSelector, so we do it here instead.
if (getCurrentModel().getTabAt(0) == null) notifyChanged();
}
};
for (TabModel model : getModels()) {
model.addObserver(tabModelObserver);
}
}
public void setTab(Tab tab) {
((SingleTabModel) getCurrentModel()).setTab(tab);
markTabStateInitialized();
}
}
......@@ -15,7 +15,6 @@ import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.text.TextUtils;
import android.util.Pair;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
......@@ -25,7 +24,6 @@ import org.chromium.base.ActivityState;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.Log;
import org.chromium.base.StrictModeContext;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.base.task.PostTask;
......@@ -48,16 +46,10 @@ import org.chromium.chrome.browser.metrics.WebApkUma;
import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabBrowserControlsConstraintsHelper;
import org.chromium.chrome.browser.tab.TabBuilder;
import org.chromium.chrome.browser.tab.TabDelegateFactory;
import org.chromium.chrome.browser.tab.TabImpl;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tab.TabObserver;
import org.chromium.chrome.browser.tab.TabSelectionType;
import org.chromium.chrome.browser.tab.TabState;
import org.chromium.chrome.browser.tab.TabThemeColorHelper;
import org.chromium.chrome.browser.tabmodel.SingleTabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate;
import org.chromium.chrome.browser.ui.system.StatusBarColorController;
import org.chromium.chrome.browser.usage_stats.UsageStatsService;
......@@ -72,7 +64,6 @@ import org.chromium.content_public.browser.UiThreadTaskTraits;
import org.chromium.net.NetworkChangeNotifier;
import org.chromium.ui.base.PageTransition;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
......@@ -89,8 +80,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
protected static final String BUNDLE_TAB_ID = "tabId";
private final WebappDirectoryManager mDirectoryManager;
private WebappInfo mWebappInfo;
private BrowserServicesIntentDataProvider mIntentDataProvider;
......@@ -153,7 +142,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
*/
public WebappActivity() {
mWebappInfo = createWebappInfo(null);
mDirectoryManager = new WebappDirectoryManager();
mDisclosureSnackbarController = new WebappDisclosureSnackbarController();
}
......@@ -211,8 +199,7 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
public void initializeState() {
super.initializeState();
createAndShowTab();
mTabController.setInitialTab(getActivityTab());
mTabController.initializeState();
initializeUI(getSavedInstanceState());
}
......@@ -385,17 +372,10 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
mIsInitialized = true;
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mDirectoryManager.cancelCleanup();
saveState(outState);
}
@Override
public void onStartWithNative() {
super.onStartWithNative();
mDirectoryManager.cleanUpDirectories(this, getActivityId());
WebappDirectoryManager.cleanUpDirectories();
}
@Override
......@@ -404,30 +384,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
getFullscreenManager().exitPersistentFullscreenMode();
}
/**
* Saves the tab data out to a file.
*/
private void saveState(Bundle outState) {
if (getActivityTab() == null || getActivityTab().getUrl() == null
|| getActivityTab().getUrl().isEmpty()) {
return;
}
outState.putInt(BUNDLE_TAB_ID, getActivityTab().getId());
String tabFileName = TabState.getTabStateFilename(getActivityTab().getId(), false);
File tabFile = new File(getActivityDirectory(), tabFileName);
// TODO(crbug.com/525785): Temporarily allowing disk access until more permanent fix is in.
try (StrictModeContext ignored = StrictModeContext.allowDiskWrites()) {
TabState.saveState(tabFile, TabState.from(getActivityTab()), false);
}
}
private TabState restoreTabState(Bundle savedInstanceState, int tabId) {
return TabState.restoreTabState(getActivityDirectory(), tabId);
}
@Override
public void onResume() {
if (!isFinishing()) {
......@@ -706,15 +662,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
return mWebappInfo.id();
}
/**
* Get the active directory by this web app.
*
* @return The directory used for the current web app.
*/
private File getActivityDirectory() {
return mDirectoryManager.getWebappDirectory(this, getActivityId());
}
@VisibleForTesting
SplashController getSplashControllerForTests() {
return mSplashController;
......@@ -732,10 +679,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
return mDelegateFactory;
}
private TabCreator createNormalTabCreator() {
return new WebappTabDelegate(false /* incognito */, mWebappInfo);
}
// We're temporarily disable CS on webapp since there are some issues. (http://crbug.com/471950)
// TODO(changwan): re-enable it once the issues are resolved.
@Override
......@@ -805,65 +748,6 @@ public class WebappActivity extends BaseCustomTabActivity<WebappActivityComponen
mSplashController.removeObserver(observer);
}
@Override
protected TabModelSelector createTabModelSelector() {
return new SingleTabModelSelector(this, this, false);
}
@Override
protected Pair<? extends TabCreator, ? extends TabCreator> createTabCreators() {
return Pair.create(createNormalTabCreator(), null);
}
protected void createAndShowTab() {
TabImpl tab = (TabImpl) createTab();
getTabModelSelector().setTab(tab);
tab.show(TabSelectionType.FROM_NEW);
}
@Override
public SingleTabModelSelector getTabModelSelector() {
return (SingleTabModelSelector) super.getTabModelSelector();
}
/**
* Creates the {@link Tab} used by the {@link SingleTabActivity}.
* If the {@code savedInstanceState} exists, then the user did not intentionally close the app
* by swiping it away in the recent tasks list. In that case, we try to restore the tab from
* disk.
*/
protected Tab createTab() {
Tab tab = null;
TabState tabState = null;
int tabId = Tab.INVALID_TAB_ID;
Bundle savedInstanceState = getSavedInstanceState();
if (savedInstanceState != null) {
tabId = savedInstanceState.getInt(BUNDLE_TAB_ID, Tab.INVALID_TAB_ID);
if (tabId != Tab.INVALID_TAB_ID) {
tabState = restoreTabState(savedInstanceState, tabId);
}
}
boolean unfreeze = tabId != Tab.INVALID_TAB_ID && tabState != null;
if (unfreeze) {
tab = TabBuilder.createFromFrozenState()
.setId(tabId)
.setWindow(getWindowAndroid())
.setDelegateFactory(createTabDelegateFactory())
.setTabState(tabState)
.setUnfreeze(unfreeze)
.build();
} else {
tab = new TabBuilder()
.setWindow(getWindowAndroid())
.setLaunchType(TabLaunchType.FROM_CHROME_UI)
.setDelegateFactory(createTabDelegateFactory())
.setTabState(tabState)
.setUnfreeze(unfreeze)
.build();
}
return tab;
}
@Override
public void onUpdateStateChanged() {}
}
......@@ -11,25 +11,39 @@ import androidx.annotation.Nullable;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.ActivityTabProvider.HintlessActivityTabObserver;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.WebContentsFactory;
import org.chromium.chrome.browser.browserservices.BrowserServicesActivityTabController;
import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory;
import org.chromium.chrome.browser.customtabs.CustomTabTabPersistencePolicy;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabFactory;
import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabProvider;
import org.chromium.chrome.browser.customtabs.content.TabCreationMode;
import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar;
import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabImpl;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelectorImpl;
import org.chromium.content_public.browser.WebContents;
import javax.inject.Inject;
import dagger.Lazy;
/**
* Shortcut/WebAPK implementation of {@link BrowserServicesActivityTabController}.
*/
@ActivityScope
public class WebappActivityTabController implements BrowserServicesActivityTabController {
private final Lazy<CustomTabDelegateFactory> mTabDelegateFactory;
private final ChromeActivity mActivity;
private final TabObserverRegistrar mTabObserverRegistrar;
private final CustomTabTabPersistencePolicy mTabPersistencePolicy;
private final CustomTabActivityTabFactory mTabFactory;
private final ActivityTabProvider mActivityTabProvider;
private final WebContentsFactory mWebContentsFactory;
private final CustomTabActivityTabProvider mTabProvider;
private final TabObserverRegistrar mTabObserverRegistrar;
private HintlessActivityTabObserver mTabSwapObserver = new HintlessActivityTabObserver() {
@Override
......@@ -39,17 +53,19 @@ public class WebappActivityTabController implements BrowserServicesActivityTabCo
};
@Inject
public WebappActivityTabController(ActivityTabProvider activityTabProvider,
CustomTabActivityTabProvider tabProvider, TabObserverRegistrar tabObserverRegistrar) {
public WebappActivityTabController(ChromeActivity activity,
Lazy<CustomTabDelegateFactory> tabDelegateFactory,
ActivityTabProvider activityTabProvider, TabObserverRegistrar tabObserverRegistrar,
CustomTabTabPersistencePolicy persistencePolicy, CustomTabActivityTabFactory tabFactory,
WebContentsFactory webContentsFactory, CustomTabActivityTabProvider tabProvider) {
mTabDelegateFactory = tabDelegateFactory;
mActivity = activity;
mTabObserverRegistrar = tabObserverRegistrar;
mTabPersistencePolicy = persistencePolicy;
mTabFactory = tabFactory;
mActivityTabProvider = activityTabProvider;
mWebContentsFactory = webContentsFactory;
mTabProvider = tabProvider;
mTabObserverRegistrar = tabObserverRegistrar;
}
public void setInitialTab(Tab tab) {
mTabProvider.setInitialTab(tab, TabCreationMode.DEFAULT);
mActivityTabProvider.addObserverAndTrigger(mTabSwapObserver);
mTabObserverRegistrar.addObserversForTab(tab);
}
@Override
......@@ -58,26 +74,94 @@ public class WebappActivityTabController implements BrowserServicesActivityTabCo
@Override
public void closeTab() {
Tab tab = mTabProvider.getTab();
if (tab == null) return;
getTabModelSelector().closeAllTabs(true);
mTabFactory.getTabModelSelector().getCurrentModel().closeTab(
mTabProvider.getTab(), false, false, false);
}
@Override
public void closeAndForgetTab() {
closeTab();
mTabFactory.getTabModelSelector().closeAllTabs(true);
mTabPersistencePolicy.deleteMetadataStateFileAsync();
}
@Override
public void saveState() {}
public void saveState() {
mTabFactory.getTabModelSelector().saveState();
}
@Override
@Nullable
public TabModelSelector getTabModelSelector() {
return mTabFactory.getTabModelSelector();
}
public void initializeState() {
TabModelSelectorImpl tabModelSelector = mTabFactory.getTabModelSelector();
TabModel tabModel = tabModelSelector.getModel(false /* incognito */);
tabModel.addObserver(mTabObserverRegistrar);
finalizeCreatingTab(tabModelSelector, tabModel);
Tab tab = mTabProvider.getTab();
if (tab == null) return null;
assert tab != null;
assert mTabProvider.getInitialTabCreationMode() != TabCreationMode.NONE;
// Put Sync in the correct state by calling tab state initialized. crbug.com/581811.
tabModelSelector.markTabStateInitialized();
}
return ((TabImpl) tab).getActivity().getTabModelSelector();
// Creates the tab on native init, if it hasn't been created yet, and does all the additional
// initialization steps necessary at this stage.
private void finalizeCreatingTab(TabModelSelectorImpl tabModelSelector, TabModel tabModel) {
Tab tab = null;
@TabCreationMode
int mode = mTabProvider.getInitialTabCreationMode();
Tab restoredTab = tryRestoringTab(tabModelSelector);
if (restoredTab != null) {
tab = restoredTab;
mode = TabCreationMode.RESTORED;
}
if (tab == null) {
// No tab was restored, creating a new tab.
tab = createTab();
mode = TabCreationMode.DEFAULT;
}
assert tab != null;
if (mode != TabCreationMode.RESTORED) {
tabModel.addTab(tab, 0, tab.getLaunchType());
}
mTabProvider.setInitialTab(tab, mode);
// Listen to tab swapping and closing.
mActivityTabProvider.addObserverAndTrigger(mTabSwapObserver);
}
@Nullable
private Tab tryRestoringTab(TabModelSelectorImpl tabModelSelector) {
if (mActivity.getSavedInstanceState() == null) return null;
tabModelSelector.loadState(true);
tabModelSelector.restoreTabs(true);
Tab tab = tabModelSelector.getCurrentTab();
if (tab != null) {
initializeTab(tab);
}
return tab;
}
private Tab createTab() {
WebContents webContents =
mWebContentsFactory.createWebContentsWithWarmRenderer(false /* incognito */, false);
Tab tab = mTabFactory.createTab(webContents, mTabDelegateFactory.get());
initializeTab(tab);
return tab;
}
private void initializeTab(Tab tab) {
mTabObserverRegistrar.addObserversForTab(tab);
}
}
......@@ -9,22 +9,30 @@ import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.provider.Browser;
import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabsIntent;
import org.chromium.base.ContextUtils;
import org.chromium.base.Log;
import org.chromium.base.PackageManagerUtils;
import org.chromium.base.StrictModeContext;
import org.chromium.base.Supplier;
import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider.LaunchSourceType;
import org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl;
import org.chromium.chrome.browser.init.StartupTabPreloader;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabDelegateFactory;
import org.chromium.chrome.browser.tab.TabIdManager;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.AsyncTabParamsManager;
import org.chromium.chrome.browser.tabmodel.ChromeTabCreator;
import org.chromium.chrome.browser.tabmodel.document.AsyncTabCreationParams;
import org.chromium.chrome.browser.tabmodel.document.TabDelegate;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.WindowAndroid;
import java.net.URISyntaxException;
import java.util.List;
......@@ -35,37 +43,78 @@ import java.util.List;
* This is the same as the parent class with exception of checking for a specialized native handlers
* first, and if none are found opening a Custom Tab instead of creating a new tab in Chrome.
*/
public class WebappTabDelegate extends TabDelegate {
public class WebappTabDelegate extends ChromeTabCreator {
private static final String TAG = "WebappTabDelegate";
private String mApkPackageName;
private @LaunchSourceType int mLaunchSourceType;
private final TabDelegate mTabDelegate;
public WebappTabDelegate(boolean incognito, WebappInfo webappInfo) {
super(incognito);
public WebappTabDelegate(WebappActivity activity, WindowAndroid nativeWindow,
StartupTabPreloader startupTabPreloader,
Supplier<TabDelegateFactory> tabDelegateFactory, boolean incognito) {
super(activity, nativeWindow, startupTabPreloader, tabDelegateFactory, incognito);
WebappInfo webappInfo = activity.getWebappInfo();
mApkPackageName = webappInfo.webApkPackageName();
mLaunchSourceType =
webappInfo.isForWebApk() ? LaunchSourceType.WEBAPK : LaunchSourceType.WEBAPP;
mTabDelegate = new TabDelegate(incognito) {
@Override
public void createNewTab(
AsyncTabCreationParams asyncParams, @TabLaunchType int type, int parentId) {
String url = asyncParams.getLoadUrlParams().getUrl();
if (maybeStartExternalActivity(url)) return;
int assignedTabId = TabIdManager.getInstance().generateValidId(Tab.INVALID_TAB_ID);
AsyncTabParamsManager.add(assignedTabId, asyncParams);
Intent intent = new CustomTabsIntent.Builder().setShowTitle(true).build().intent;
intent.setData(Uri.parse(url));
intent.putExtra(
CustomTabIntentDataProvider.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER, true);
intent.putExtra(CustomTabIntentDataProvider.EXTRA_IS_OPENED_BY_CHROME, true);
intent.putExtra(CustomTabIntentDataProvider.EXTRA_IS_OPENED_BY_WEBAPK, true);
intent.putExtra(
CustomTabIntentDataProvider.EXTRA_BROWSER_LAUNCH_SOURCE, mLaunchSourceType);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, mApkPackageName);
addAsyncTabExtras(
asyncParams, parentId, false /* isChromeUI */, assignedTabId, intent);
IntentHandler.startActivityForTrustedIntent(intent);
}
};
}
@Override
public boolean createsTabsAsynchronously() {
return mTabDelegate.createsTabsAsynchronously();
}
@Override
@Nullable
public Tab createNewTab(LoadUrlParams loadUrlParams, @TabLaunchType int type, Tab parent) {
if (type != TabLaunchType.FROM_RESTORE) {
return mTabDelegate.createNewTab(loadUrlParams, type, parent);
}
return super.createNewTab(loadUrlParams, type, parent);
}
@Override
public void createNewTab(
AsyncTabCreationParams asyncParams, @TabLaunchType int type, int parentId) {
String url = asyncParams.getLoadUrlParams().getUrl();
if (maybeStartExternalActivity(url)) return;
int assignedTabId = TabIdManager.getInstance().generateValidId(Tab.INVALID_TAB_ID);
AsyncTabParamsManager.add(assignedTabId, asyncParams);
Intent intent = new CustomTabsIntent.Builder().setShowTitle(true).build().intent;
intent.setData(Uri.parse(url));
intent.putExtra(CustomTabIntentDataProvider.EXTRA_SEND_TO_EXTERNAL_DEFAULT_HANDLER, true);
intent.putExtra(CustomTabIntentDataProvider.EXTRA_IS_OPENED_BY_CHROME, true);
intent.putExtra(CustomTabIntentDataProvider.EXTRA_IS_OPENED_BY_WEBAPK, true);
intent.putExtra(CustomTabIntentDataProvider.EXTRA_BROWSER_LAUNCH_SOURCE, mLaunchSourceType);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, mApkPackageName);
addAsyncTabExtras(asyncParams, parentId, false /* isChromeUI */, assignedTabId, intent);
IntentHandler.startActivityForTrustedIntent(intent);
@Nullable
public Tab launchUrl(String url, @TabLaunchType int type) {
if (type != TabLaunchType.FROM_RESTORE) {
return mTabDelegate.launchUrl(url, type);
}
return super.launchUrl(url, type);
}
@Override
public boolean createTabWithWebContents(
@Nullable Tab parent, WebContents webContents, @TabLaunchType int type, String url) {
if (type != TabLaunchType.FROM_RESTORE) {
return mTabDelegate.createTabWithWebContents(parent, webContents, type, url);
}
return super.createTabWithWebContents(parent, webContents, type, url);
}
private boolean maybeStartExternalActivity(String url) {
......
......@@ -9,6 +9,7 @@ import androidx.annotation.Nullable;
import org.chromium.chrome.browser.browserservices.BrowserServicesActivityTabController;
import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.customtabs.CustomTabUmaRecorder;
import org.chromium.chrome.browser.init.StartupTabPreloader;
import org.chromium.chrome.browser.webapps.WebappActivityTabController;
import dagger.Module;
......@@ -43,4 +44,10 @@ public final class WebappActivityModule {
public CustomTabUmaRecorder provideCustomTabUmaRecorder() {
return null;
}
@Nullable
@Provides
public StartupTabPreloader provideStartupTabPreloader() {
return null;
}
}
......@@ -26,7 +26,6 @@ import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.ChromeTabbedActivity;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.SingleTabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
......@@ -71,13 +70,9 @@ public class CloseTabDirectActionHandlerTest {
assertThat(
mSelector.getCurrentTab(), Matchers.not(Matchers.sameInstance(initiallyCurrent)));
if (!(mSelector instanceof SingleTabModelSelector)) {
assertEquals(1, mSelector.getTotalTabCount());
// Close last tab
performAction("close_tab");
} else {
assertEquals(0, mSelector.getTotalTabCount());
}
assertEquals(1, mSelector.getTotalTabCount());
// Close last tab
performAction("close_tab");
// No tabs are left, so actions aren't available anymore.
assertThat(getDirectActions(), Matchers.empty());
......
......@@ -27,7 +27,6 @@ import org.chromium.base.test.util.MinAndroidSdkLevel;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.tabmodel.SingleTabModelSelector;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
......@@ -91,8 +90,6 @@ public class MenuDirectActionHandlerTest {
Matchers.containsInAnyOrder("bookmark_this_page", "reload", "downloads", "help",
"new_tab", "open_history", "preferences", "close_all_tabs"));
// Tabs can't be closed for SingleTab Activities.
if (mTabModelSelector instanceof SingleTabModelSelector) return;
TestThreadUtils.runOnUiThreadBlocking(() -> { mTabModelSelector.closeAllTabs(); });
// Wait for any pending animations for tab closures to complete.
CriteriaHelper.pollUiThread(Criteria.equals(0, () -> mTabModelSelector.getTotalTabCount()));
......
......@@ -36,7 +36,6 @@ import org.chromium.chrome.browser.tab.EmptyTabObserver;
import org.chromium.chrome.browser.tab.InterceptNavigationDelegateImpl;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tabmodel.EmptyTabModelSelectorObserver;
import org.chromium.chrome.browser.tabmodel.SingleTabModel;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.content_public.browser.LoadUrlParams;
......@@ -402,30 +401,24 @@ public class UrlOverridingTest {
@SmallTest
@RetryOnFailure
public void testOpenWindowFromUserGesture() {
boolean opensNewTab =
!(mActivityTestRule.getActivity().getCurrentTabModel() instanceof SingleTabModel);
loadUrlAndWaitForIntentUrl(mTestServer.getURL(OPEN_WINDOW_FROM_USER_GESTURE_PAGE), true,
opensNewTab, true, null, true);
true, true, null, true);
}
@Test
@SmallTest
@RetryOnFailure
public void testOpenWindowFromLinkUserGesture() {
boolean opensNewTab =
!(mActivityTestRule.getActivity().getCurrentTabModel() instanceof SingleTabModel);
loadUrlAndWaitForIntentUrl(mTestServer.getURL(OPEN_WINDOW_FROM_LINK_USER_GESTURE_PAGE),
true, opensNewTab, true, null, true, "link");
true, true, true, null, true, "link");
}
@Test
@SmallTest
@RetryOnFailure
public void testOpenWindowFromSvgUserGesture() {
boolean opensNewTab =
!(mActivityTestRule.getActivity().getCurrentTabModel() instanceof SingleTabModel);
loadUrlAndWaitForIntentUrl(mTestServer.getURL(OPEN_WINDOW_FROM_SVG_USER_GESTURE_PAGE), true,
opensNewTab, true, null, true, "link");
true, true, null, true, "link");
}
@Test
......
......@@ -5,10 +5,7 @@
package org.chromium.chrome.browser.webapps;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import org.junit.After;
import org.junit.Assert;
......@@ -21,6 +18,7 @@ import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.shadows.ShadowLooper;
import org.chromium.base.ContextUtils;
import org.chromium.base.PathUtils;
import org.chromium.base.ThreadUtils;
import org.chromium.base.metrics.RecordHistogram;
......@@ -29,11 +27,8 @@ import org.chromium.base.task.test.CustomShadowAsyncTask;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Feature;
import org.chromium.webapk.lib.common.WebApkConstants;
import org.chromium.webapk.test.WebApkTestHelper;
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
......@@ -46,38 +41,22 @@ public class WebappDirectoryManagerTest {
@Rule
public MockWebappDataStorageClockRule mClockRule = new MockWebappDataStorageClockRule();
private static final String WEBAPP_ID_1 = "webapp_1";
private static final String WEBAPP_ID_2 = "webapp_2";
private static final String WEBAPP_ID_3 = "webapp_3";
private static final String WEBAPK_PACKAGE_NAME_1 = "webapk_1";
private static final String WEBAPK_PACKAGE_NAME_2 = "webapk_2";
private static final String WEBAPK_PACKAGE_NAME_3 = "webapk_3";
private static final String WEBAPK_ID_1 =
WebApkConstants.WEBAPK_ID_PREFIX + WEBAPK_PACKAGE_NAME_1;
private static final String WEBAPK_ID_2 =
WebApkConstants.WEBAPK_ID_PREFIX + WEBAPK_PACKAGE_NAME_2;
private static final String WEBAPK_ID_3 =
WebApkConstants.WEBAPK_ID_PREFIX + WEBAPK_PACKAGE_NAME_3;
private static class TestWebappDirectoryManager extends WebappDirectoryManager {
private Set<Intent> mBaseIntents = new HashSet<Intent>();
@Override
protected Set<Intent> getBaseIntentsForAllTasks() {
return mBaseIntents;
}
}
private Context mContext;
private TestWebappDirectoryManager mWebappDirectoryManager;
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
ContextUtils.initApplicationContext(mContext);
ThreadUtils.setThreadAssertsDisabledForTesting(true);
PathUtils.setPrivateDataDirectorySuffix("chrome");
mWebappDirectoryManager = new TestWebappDirectoryManager();
mWebappDirectoryManager.resetForTesting();
WebappDirectoryManager.resetForTesting();
}
@After
......@@ -96,101 +75,25 @@ public class WebappDirectoryManagerTest {
@Test
@Feature({"Webapps"})
public void testDeletesOwnDirectory() throws Exception {
File webappDirectory =
new File(mWebappDirectoryManager.getBaseWebappDirectory(mContext), WEBAPP_ID_1);
Assert.assertTrue(webappDirectory.mkdirs());
Assert.assertTrue(webappDirectory.exists());
// Confirm that it deletes the current web app's directory.
runCleanup();
Assert.assertFalse(webappDirectory.exists());
}
/**
* On Lollipop and higher, the {@link WebappDirectoryManager} also deletes directories for web
* apps that no longer correspond to tasks in Recents.
*/
@Test
@Feature({"Webapps"})
public void testDeletesDirectoriesForDeadTasks() throws Exception {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
// Track the three web app directories.
File directory1 =
new File(mWebappDirectoryManager.getBaseWebappDirectory(mContext), WEBAPP_ID_1);
File directory2 =
new File(mWebappDirectoryManager.getBaseWebappDirectory(mContext), WEBAPP_ID_2);
File directory3 =
new File(mWebappDirectoryManager.getBaseWebappDirectory(mContext), WEBAPP_ID_3);
// Seed the directory with folders for web apps.
Assert.assertTrue(directory1.mkdirs());
Assert.assertTrue(directory2.mkdirs());
Assert.assertTrue(directory3.mkdirs());
// Indicate that another of the web apps is listed in Recents; in real usage this web app
// would not be in the foreground and would have persisted its state.
mWebappDirectoryManager.mBaseIntents = new HashSet<Intent>();
mWebappDirectoryManager.mBaseIntents.add(
new Intent(Intent.ACTION_VIEW, Uri.parse("webapp://webapp_2")));
// Only the directory for the background web app should survive.
runCleanup();
Assert.assertFalse(directory1.exists());
Assert.assertTrue(directory2.exists());
Assert.assertFalse(directory3.exists());
}
/**
* On Lollipop and higher, the {@link WebappDirectoryManager} also deletes directories for
* *WebApks* that are no longer installed.
*/
@Test
@Feature({"Webapps"})
public void testDeletesDirectoriesForUninstalledWebApks() throws Exception {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
WebApkTestHelper.registerWebApkWithMetaData(WEBAPK_PACKAGE_NAME_2, new Bundle(), null);
// Track the three web app directories.
File directory1 =
new File(mWebappDirectoryManager.getBaseWebappDirectory(mContext), WEBAPK_ID_1);
File directory2 =
new File(mWebappDirectoryManager.getBaseWebappDirectory(mContext), WEBAPK_ID_2);
File directory3 =
new File(mWebappDirectoryManager.getBaseWebappDirectory(mContext), WEBAPK_ID_3);
// Seed the directory with folders for web apps.
Assert.assertTrue(directory1.mkdirs());
Assert.assertTrue(directory2.mkdirs());
Assert.assertTrue(directory3.mkdirs());
// Only the directory for the still installed WebAPK should survive.
runCleanup();
Assert.assertFalse(directory1.exists());
Assert.assertTrue(directory2.exists());
Assert.assertFalse(directory3.exists());
}
@Test
@Feature({"Webapps"})
public void testDeletesObsoleteDirectories() throws Exception {
public void testDeletesObsoleteDirectories() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
// Seed the base directory with folders that correspond to pre-L web apps.
File baseDirectory = mContext.getDataDir();
File webappDirectory1 = new File(baseDirectory, "app_WebappActivity1");
File webappDirectory6 = new File(baseDirectory, "app_WebappActivity6");
File webappDirectory = new File(baseDirectory, "app_WebappActivity");
File nonWebappDirectory = new File(baseDirectory, "app_ChromeDocumentActivity");
Assert.assertTrue(webappDirectory1.mkdirs());
Assert.assertTrue(webappDirectory6.mkdirs());
Assert.assertTrue(webappDirectory.mkdirs());
Assert.assertTrue(nonWebappDirectory.mkdirs());
// Make sure only the web app folders are deleted.
runCleanup();
Assert.assertFalse(webappDirectory1.exists());
Assert.assertFalse(webappDirectory6.exists());
Assert.assertFalse(webappDirectory.exists());
Assert.assertTrue(nonWebappDirectory.exists());
Assert.assertTrue(webappDirectory.mkdirs());
// Make sure the second cleanup call no-ops.
runCleanup();
Assert.assertTrue(webappDirectory.exists());
Assert.assertTrue(nonWebappDirectory.exists());
}
......@@ -200,7 +103,7 @@ public class WebappDirectoryManagerTest {
*/
@Test
@Feature({"Webapps"})
public void testCountsUpdateFilesForUninstalledWebApks() throws Exception {
public void testCountsUpdateFilesForUninstalledWebApks() {
File directory1 = new File(WebappDirectoryManager.getWebApkUpdateDirectory(), WEBAPK_ID_1);
directory1.mkdirs();
File directory2 = new File(WebappDirectoryManager.getWebApkUpdateDirectory(), WEBAPK_ID_2);
......@@ -221,7 +124,7 @@ public class WebappDirectoryManagerTest {
*/
@Test
@Feature({"Webapps"})
public void testCountsOldWebApkUpdateFiles() throws Exception {
public void testCountsOldWebApkUpdateFiles() {
File directory = new File(WebappDirectoryManager.getWebApkUpdateDirectory(), WEBAPK_ID_1);
directory.mkdirs();
registerWebapp(WEBAPK_ID_1);
......@@ -242,7 +145,7 @@ public class WebappDirectoryManagerTest {
*/
@Test
@Feature({"Webapps"})
public void testDoesNotCountFilesForNewlyScheduledUpdates() throws Exception {
public void testDoesNotCountFilesForNewlyScheduledUpdates() {
File directory = new File(WebappDirectoryManager.getWebApkUpdateDirectory(), WEBAPK_ID_1);
directory.mkdirs();
registerWebapp(WEBAPK_ID_1);
......@@ -256,8 +159,8 @@ public class WebappDirectoryManagerTest {
"WebApk.Update.NumStaleUpdateRequestFiles", 1));
}
private void runCleanup() throws Exception {
mWebappDirectoryManager.cleanUpDirectories(mContext, WEBAPP_ID_1);
private void runCleanup() {
WebappDirectoryManager.cleanUpDirectories();
ShadowLooper.runUiThreadTasksIncludingDelayedTasks();
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment