Commit 090f1f05 authored by Pavel Shmakov's avatar Pavel Shmakov Committed by Commit Bot

Migrate TrustedWebActivityUi and related classes to Dagger, decouple CustomTabActivity from it.

As a first step of simplifying CustomTabActivity, I extract all the code related
to TrustedWebActivityUi and use Dagger to organize dependencies for
TrustedWebActivityUi.

I make use of recently introduced activity lifecycle dispatching: https://crrev.com/c/1283256

Bug: 887926
Change-Id: Ia36a026a7f297e7c0f101189945c44454d12fa6e
Reviewed-on: https://chromium-review.googlesource.com/c/1281102
Commit-Queue: Pavel Shmakov <pshmakov@chromium.org>
Reviewed-by: default avatarYusuf Ozuysal <yusufo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#603122}
parent 78b9bb38
// Copyright 2018 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;
import org.chromium.chrome.browser.customtabs.CustomTabsConnection;
import dagger.Module;
import dagger.Provides;
/**
* Makes entities provided by AppHooks available for injection with Dagger.
* TODO(pshmakov): merge this with Chrome's AppHooksImpl.
*/
@Module
public class AppHooksModule {
@Provides
public static CustomTabsConnection provideCustomTabsConnection() {
return CustomTabsConnection.getInstance();
}
}
...@@ -4,16 +4,23 @@ ...@@ -4,16 +4,23 @@
package org.chromium.chrome.browser.browserservices; package org.chromium.chrome.browser.browserservices;
import static org.chromium.chrome.browser.dependency_injection.ChromeCommonQualifiers.APP_CONTEXT;
import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.text.TextUtils; import android.text.TextUtils;
import org.chromium.base.Log; import org.chromium.base.Log;
import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.chrome.browser.util.UrlUtilities; import org.chromium.chrome.browser.util.UrlUtilities;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
/** /**
* Takes care of recording that Chrome contains data for the client app in the * Takes care of recording that Chrome contains data for the client app in the
* {@link ClientAppDataRegister}. It performs three main duties: * {@link ClientAppDataRegister}. It performs three main duties:
...@@ -25,15 +32,14 @@ import java.util.Set; ...@@ -25,15 +32,14 @@ import java.util.Set;
* {@link TrustedWebActivityUi}. Having more instances won't effect correctness, but will limit the * {@link TrustedWebActivityUi}. Having more instances won't effect correctness, but will limit the
* performance benefits of the cache. * performance benefits of the cache.
* Thread safety: All methods on this class should be called from the same thread. * Thread safety: All methods on this class should be called from the same thread.
* Native: The default {@link UrlTransformer} requires native to be loaded.
*/ */
@ActivityScope
public class ClientAppDataRecorder { public class ClientAppDataRecorder {
private static final String TAG = "TWAClientAppData"; private static final String TAG = "TWAClientAppData";
private final PackageManager mPackageManager; private final PackageManager mPackageManager;
/** Underlying data register. */ /** Underlying data register. */
private final ClientAppDataRegister mClientAppDataRegister; private final ClientAppDataRegister mClientAppDataRegister;
private final UrlTransformer mUrlTransformer;
/** /**
* Cache so we don't send the same request multiple times. {@link #register} is called on each * Cache so we don't send the same request multiple times. {@link #register} is called on each
...@@ -42,31 +48,18 @@ public class ClientAppDataRecorder { ...@@ -42,31 +48,18 @@ public class ClientAppDataRecorder {
*/ */
private final Set<String> mCache = new HashSet<>(); private final Set<String> mCache = new HashSet<>();
/** Class to allow mocking native calls in unit tests. */ @Inject
/* package */ static class UrlTransformer { public ClientAppDataRecorder(@Named(APP_CONTEXT) Context context,
/* package */ String getDomain(Origin origin) { ClientAppDataRegister clientAppDataRegister) {
return UrlUtilities.getDomainAndRegistry( mPackageManager = context.getPackageManager();
origin.toString(), true /* includePrivateRegistries */);
}
}
/** Creates a ClientAppDataRecorder with default dependencies. */
public ClientAppDataRecorder(PackageManager packageManager) {
this(packageManager, new ClientAppDataRegister(), new UrlTransformer());
}
/** Creates a ClientAppDataRecorder providing all dependencies. */
public ClientAppDataRecorder(PackageManager packageManager,
ClientAppDataRegister clientAppDataRegister, UrlTransformer urlTransformer) {
mPackageManager = packageManager;
mClientAppDataRegister = clientAppDataRegister; mClientAppDataRegister = clientAppDataRegister;
mUrlTransformer = urlTransformer;
} }
/** /**
* Calls {@link ClientAppDataRegister#registerPackageForDomain}, looking up the uid * Calls {@link ClientAppDataRegister#registerPackageForDomain}, looking up the uid
* and app name for the |packageName|, extracting the domain from the origin and deduplicating * and app name for the |packageName|, extracting the domain from the origin and deduplicating
* multiple requests with the same parameters. * multiple requests with the same parameters.
* Requires native to be loaded.
*/ */
/* package */ void register(String packageName, Origin origin) { /* package */ void register(String packageName, Origin origin) {
if (mCache.contains(combine(packageName, origin))) return; if (mCache.contains(combine(packageName, origin))) return;
...@@ -82,7 +75,8 @@ public class ClientAppDataRecorder { ...@@ -82,7 +75,8 @@ public class ClientAppDataRecorder {
return; return;
} }
String domain = mUrlTransformer.getDomain(origin); String domain = UrlUtilities.getDomainAndRegistry(
origin.toString(), true /*includePrivateRegistries*/);
Log.d(TAG, "Registering %d (%s) for %s", ai.uid, appLabel, domain); Log.d(TAG, "Registering %d (%s) for %s", ai.uid, appLabel, domain);
mClientAppDataRegister.registerPackageForDomain(ai.uid, appLabel, domain); mClientAppDataRegister.registerPackageForDomain(ai.uid, appLabel, domain);
......
...@@ -14,6 +14,8 @@ import org.chromium.chrome.browser.snackbar.SnackbarManager; ...@@ -14,6 +14,8 @@ import org.chromium.chrome.browser.snackbar.SnackbarManager;
import javax.inject.Inject; import javax.inject.Inject;
import dagger.Lazy;
/** /**
* Shows the Trusted Web Activity disclosure when appropriate and records its acceptance. * Shows the Trusted Web Activity disclosure when appropriate and records its acceptance.
* *
...@@ -26,6 +28,7 @@ public class TrustedWebActivityDisclosure { ...@@ -26,6 +28,7 @@ public class TrustedWebActivityDisclosure {
// TODO(peconn): Make this package private once TrustedWebActivityUi can be injected. // TODO(peconn): Make this package private once TrustedWebActivityUi can be injected.
private final Resources mResources; private final Resources mResources;
private final ChromePreferenceManager mPreferenceManager; private final ChromePreferenceManager mPreferenceManager;
private final Lazy<SnackbarManager> mSnackbarManager;
private boolean mSnackbarShowing; private boolean mSnackbarShowing;
...@@ -50,30 +53,31 @@ public class TrustedWebActivityDisclosure { ...@@ -50,30 +53,31 @@ public class TrustedWebActivityDisclosure {
@Inject @Inject
/* package */ TrustedWebActivityDisclosure(Resources resources, /* package */ TrustedWebActivityDisclosure(Resources resources,
ChromePreferenceManager preferenceManager) { ChromePreferenceManager preferenceManager, Lazy<SnackbarManager> snackbarManager) {
mResources = resources; mResources = resources;
mPreferenceManager = preferenceManager; mPreferenceManager = preferenceManager;
mSnackbarManager = snackbarManager;
} }
/** Dismisses the Snackbar if it is showing. */ /** Dismisses the disclosure if it is showing. */
/* package */ void dismissSnackbarIfNeeded(SnackbarManager snackbarManager) { /* package */ void dismiss() {
if (!mSnackbarShowing) return; if (!mSnackbarShowing) return;
snackbarManager.dismissSnackbars(mSnackbarController); mSnackbarManager.get().dismissSnackbars(mSnackbarController);
mSnackbarShowing = false; mSnackbarShowing = false;
} }
/** Shows the Snackbar if it is not already showing and hasn't been accepted. */ /** Shows the disclosure if it is not already showing and hasn't been accepted. */
/* package */ void showSnackbarIfNeeded(SnackbarManager snackbarManager, String packageName) { /* package */ void showIfNeeded(String packageName) {
if (mSnackbarShowing) return; if (mSnackbarShowing) return;
if (wasSnackbarDismissed(packageName)) return; if (wasDismissed(packageName)) return;
snackbarManager.showSnackbar(makeRunningInChromeInfobar(packageName)); mSnackbarManager.get().showSnackbar(makeRunningInChromeInfobar(packageName));
mSnackbarShowing = true; mSnackbarShowing = true;
} }
/** Has a Snackbar been dismissed for this client package before? */ /** Has a disclosure been dismissed for this client package before? */
private boolean wasSnackbarDismissed(String packageName) { private boolean wasDismissed(String packageName) {
return mPreferenceManager.hasUserAcceptedTwaDisclosureForPackage(packageName); return mPreferenceManager.hasUserAcceptedTwaDisclosureForPackage(packageName);
} }
......
// Copyright 2018 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.customtabs;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
import org.chromium.chrome.browser.tab.BrowserControlsVisibilityDelegate;
import org.chromium.chrome.browser.tab.Tab;
import javax.inject.Inject;
/**
* Implementation of {@link BrowserControlsVisibilityDelegate} for custom tabs.
*/
@ActivityScope
public class CustomTabBrowserControlsVisibilityDelegate
implements BrowserControlsVisibilityDelegate {
private final BrowserControlsVisibilityDelegate mFullscreenManagerDelegate;
private final ActivityTabProvider mTabProvider;
private boolean mIsInTwaMode;
@Inject
public CustomTabBrowserControlsVisibilityDelegate(
ChromeFullscreenManager fullscreenManager, ActivityTabProvider tabProvider) {
mFullscreenManagerDelegate = fullscreenManager.getBrowserVisibilityDelegate();
mTabProvider = tabProvider;
}
/**
* Sets trusted web activity mode. In trusted web activity mode browser controls should be
* hidden.
*/
public void setTrustedWebActivityMode(boolean isInTwaMode) {
if (mIsInTwaMode == isInTwaMode) {
return;
}
mIsInTwaMode = isInTwaMode;
Tab activeTab = mTabProvider.getActivityTab();
if (activeTab != null) {
activeTab.updateFullscreenEnabledState();
}
}
@Override
public boolean canShowBrowserControls() {
return !mIsInTwaMode && mFullscreenManagerDelegate.canShowBrowserControls();
}
@Override
public boolean canAutoHideBrowserControls() {
return mFullscreenManagerDelegate.canAutoHideBrowserControls();
}
}
...@@ -35,8 +35,10 @@ import org.chromium.chrome.browser.ChromeFeatureList; ...@@ -35,8 +35,10 @@ import org.chromium.chrome.browser.ChromeFeatureList;
import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.ChromeVersionInfo; import org.chromium.chrome.browser.ChromeVersionInfo;
import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.IntentHandler;
import org.chromium.chrome.browser.UrlConstants;
import org.chromium.chrome.browser.browserservices.BrowserSessionDataProvider; import org.chromium.chrome.browser.browserservices.BrowserSessionDataProvider;
import org.chromium.chrome.browser.externalauth.ExternalAuthUtils; import org.chromium.chrome.browser.externalauth.ExternalAuthUtils;
import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
import org.chromium.chrome.browser.util.ColorUtils; import org.chromium.chrome.browser.util.ColorUtils;
import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.chrome.browser.util.IntentUtils;
import org.chromium.chrome.browser.widget.TintedDrawable; import org.chromium.chrome.browser.widget.TintedDrawable;
...@@ -143,6 +145,8 @@ public class CustomTabIntentDataProvider extends BrowserSessionDataProvider { ...@@ -143,6 +145,8 @@ public class CustomTabIntentDataProvider extends BrowserSessionDataProvider {
+ "To make locally-built Chrome a first-party app, sign with release-test " + "To make locally-built Chrome a first-party app, sign with release-test "
+ "signing keys and run on userdebug devices. See use_signing_keys GN arg."; + "signing keys and run on userdebug devices. See use_signing_keys GN arg.";
private final Intent mIntent;
private final int mUiType; private final int mUiType;
private final int mTitleVisibilityState; private final int mTitleVisibilityState;
private final String mMediaViewerUrl; private final String mMediaViewerUrl;
...@@ -156,6 +160,8 @@ public class CustomTabIntentDataProvider extends BrowserSessionDataProvider { ...@@ -156,6 +160,8 @@ public class CustomTabIntentDataProvider extends BrowserSessionDataProvider {
@Nullable @Nullable
private final ComponentName mModuleComponentName; private final ComponentName mModuleComponentName;
private final boolean mIsIncognito; private final boolean mIsIncognito;
@Nullable
private String mUrlToLoad;
private int mToolbarColor; private int mToolbarColor;
private int mBottomBarColor; private int mBottomBarColor;
...@@ -200,6 +206,7 @@ public class CustomTabIntentDataProvider extends BrowserSessionDataProvider { ...@@ -200,6 +206,7 @@ public class CustomTabIntentDataProvider extends BrowserSessionDataProvider {
super(intent); super(intent);
if (intent == null) assert false; if (intent == null) assert false;
mIntent = intent;
mIsOpenedByChrome = IntentUtils.safeGetBooleanExtra( mIsOpenedByChrome = IntentUtils.safeGetBooleanExtra(
intent, EXTRA_IS_OPENED_BY_CHROME, false); intent, EXTRA_IS_OPENED_BY_CHROME, false);
...@@ -407,6 +414,40 @@ public class CustomTabIntentDataProvider extends BrowserSessionDataProvider { ...@@ -407,6 +414,40 @@ public class CustomTabIntentDataProvider extends BrowserSessionDataProvider {
return color | 0xFF000000; return color | 0xFF000000;
} }
private String resolveUrlToLoad(Intent intent) {
String url = IntentHandler.getUrlFromIntent(intent);
// Intents fired for media viewers have an additional file:// URI passed along so that the
// tab can display the actual filename to the user when it is loaded.
if (isMediaViewer()) {
String mediaViewerUrl = getMediaViewerUrl();
if (!TextUtils.isEmpty(mediaViewerUrl)) {
Uri mediaViewerUri = Uri.parse(mediaViewerUrl);
if (UrlConstants.FILE_SCHEME.equals(mediaViewerUri.getScheme())) {
url = mediaViewerUrl;
}
}
}
if (!TextUtils.isEmpty(url)) {
url = DataReductionProxySettings.getInstance().maybeRewriteWebliteUrl(url);
}
return url;
}
/**
* @return The URL that should be used from this intent. If it is a WebLite url, it may be
* overridden if the Data Reduction Proxy is using Lo-Fi previews.
* Must be called only after native has loaded.
*/
public String getUrlToLoad() {
if (mUrlToLoad == null) {
mUrlToLoad = resolveUrlToLoad(mIntent);
}
return mUrlToLoad;
}
/** /**
* @return Whether url bar hiding should be enabled in the custom tab. Default is false. * @return Whether url bar hiding should be enabled in the custom tab. Default is false.
* It should be impossible to hide the url bar when the tab is opened for Payment Request. * It should be impossible to hide the url bar when the tab is opened for Payment Request.
......
...@@ -2,10 +2,14 @@ ...@@ -2,10 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
package org.chromium.chrome.browser.dependency_injection; package org.chromium.chrome.browser.customtabs.dependency_injection;
import org.chromium.chrome.browser.browserservices.TrustedWebActivityDisclosure; import org.chromium.chrome.browser.browserservices.TrustedWebActivityUi;
import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsModule; import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsModule;
import org.chromium.chrome.browser.customtabs.CustomTabBrowserControlsVisibilityDelegate;
import org.chromium.chrome.browser.dependency_injection.ActivityScope;
import org.chromium.chrome.browser.dependency_injection.ChromeActivityCommonsModule;
import org.chromium.chrome.browser.dependency_injection.ChromeActivityComponent;
import dagger.Subcomponent; import dagger.Subcomponent;
...@@ -13,8 +17,10 @@ import dagger.Subcomponent; ...@@ -13,8 +17,10 @@ import dagger.Subcomponent;
* Activity-scoped component associated with * Activity-scoped component associated with
* {@link org.chromium.chrome.browser.customtabs.CustomTabActivity}. * {@link org.chromium.chrome.browser.customtabs.CustomTabActivity}.
*/ */
@Subcomponent(modules = {ChromeActivityCommonsModule.class, ContextualSuggestionsModule.class}) @Subcomponent(modules = {ChromeActivityCommonsModule.class, ContextualSuggestionsModule.class,
CustomTabActivityModule.class})
@ActivityScope @ActivityScope
public interface CustomTabActivityComponent extends ChromeActivityComponent { public interface CustomTabActivityComponent extends ChromeActivityComponent {
TrustedWebActivityDisclosure resolveTrustedWebActivityDisclosure(); TrustedWebActivityUi resolveTrustedWebActivityUi();
CustomTabBrowserControlsVisibilityDelegate resolveControlsVisibilityDelegate();
} }
// Copyright 2018 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.customtabs.dependency_injection;
import org.chromium.chrome.browser.browserservices.ClientAppDataRegister;
import org.chromium.chrome.browser.customtabs.CustomTabIntentDataProvider;
import org.chromium.chrome.browser.customtabs.TabObserverRegistrar;
import dagger.Module;
import dagger.Provides;
/**
* Module for custom tab specific bindings.
*/
@Module
public class CustomTabActivityModule {
private final CustomTabIntentDataProvider mIntentDataProvider;
private final TabObserverRegistrar mTabObserverRegistrar;
public CustomTabActivityModule(CustomTabIntentDataProvider intentDataProvider,
TabObserverRegistrar tabObserverRegistrar) {
mIntentDataProvider = intentDataProvider;
mTabObserverRegistrar = tabObserverRegistrar;
}
@Provides
public CustomTabIntentDataProvider provideIntentDataProvider() {
return mIntentDataProvider;
}
@Provides
public ClientAppDataRegister provideClientAppDataRegister() {
return new ClientAppDataRegister();
}
@Provides
public TabObserverRegistrar provideTabObserverRegistrar() {
return mTabObserverRegistrar;
}
}
...@@ -4,16 +4,23 @@ ...@@ -4,16 +4,23 @@
package org.chromium.chrome.browser.dependency_injection; package org.chromium.chrome.browser.dependency_injection;
import static org.chromium.chrome.browser.dependency_injection.ChromeCommonQualifiers.ACTIVITY_CONTEXT;
import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import org.chromium.chrome.browser.ActivityTabProvider;
import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.compositor.layouts.LayoutManager; import org.chromium.chrome.browser.compositor.layouts.LayoutManager;
import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager; import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
import org.chromium.chrome.browser.init.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.init.ActivityLifecycleDispatcher;
import org.chromium.chrome.browser.snackbar.SnackbarManager;
import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.chrome.browser.toolbar.ToolbarManager; import org.chromium.chrome.browser.toolbar.ToolbarManager;
import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController; import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetController;
import javax.inject.Named;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
...@@ -64,8 +71,14 @@ public class ChromeActivityCommonsModule { ...@@ -64,8 +71,14 @@ public class ChromeActivityCommonsModule {
@Provides @Provides
public ChromeActivity provideChromeActivity() { public ChromeActivity provideChromeActivity() {
// Ideally this should provide only the Context instead of specific activity, but currently // Ideally providing Context should be enough, but currently a lot of code is coupled
// a lot of code is coupled specifically to ChromeActivity. // specifically to ChromeActivity.
return mActivity;
}
@Provides
@Named(ACTIVITY_CONTEXT)
public Context provideContext() {
return mActivity; return mActivity;
} }
...@@ -78,4 +91,14 @@ public class ChromeActivityCommonsModule { ...@@ -78,4 +91,14 @@ public class ChromeActivityCommonsModule {
public ActivityLifecycleDispatcher provideLifecycleDispatcher() { public ActivityLifecycleDispatcher provideLifecycleDispatcher() {
return mLifecycleDispatcher; return mLifecycleDispatcher;
} }
@Provides
public SnackbarManager provideSnackbarManager() {
return mActivity.getSnackbarManager();
}
@Provides
public ActivityTabProvider provideActivityTabProvider() {
return mActivity.getActivityTabProvider();
}
} }
...@@ -4,8 +4,11 @@ ...@@ -4,8 +4,11 @@
package org.chromium.chrome.browser.dependency_injection; package org.chromium.chrome.browser.dependency_injection;
import org.chromium.chrome.browser.AppHooksModule;
import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsModule; import org.chromium.chrome.browser.contextual_suggestions.ContextualSuggestionsModule;
import org.chromium.chrome.browser.contextual_suggestions.EnabledStateMonitor; import org.chromium.chrome.browser.contextual_suggestions.EnabledStateMonitor;
import org.chromium.chrome.browser.customtabs.dependency_injection.CustomTabActivityComponent;
import org.chromium.chrome.browser.customtabs.dependency_injection.CustomTabActivityModule;
import javax.inject.Singleton; import javax.inject.Singleton;
...@@ -14,14 +17,15 @@ import dagger.Component; ...@@ -14,14 +17,15 @@ import dagger.Component;
/** /**
* Component representing the Singletons in the main process of the application. * Component representing the Singletons in the main process of the application.
*/ */
@Component(modules = {ChromeAppModule.class}) @Component(modules = {ChromeAppModule.class, AppHooksModule.class})
@Singleton @Singleton
public interface ChromeAppComponent { public interface ChromeAppComponent {
ChromeActivityComponent createChromeActivityComponent(ChromeActivityCommonsModule module, ChromeActivityComponent createChromeActivityComponent(ChromeActivityCommonsModule module,
ContextualSuggestionsModule contextualSuggestionsModule); ContextualSuggestionsModule contextualSuggestionsModule);
CustomTabActivityComponent createCustomTabActivityComponent(ChromeActivityCommonsModule module, CustomTabActivityComponent createCustomTabActivityComponent(ChromeActivityCommonsModule module,
ContextualSuggestionsModule contextualSuggestionsModule); ContextualSuggestionsModule contextualSuggestionsModule,
CustomTabActivityModule customTabActivityModule);
// Temporary getters for DI migration process. All of these getters // Temporary getters for DI migration process. All of these getters
// should eventually be replaced with constructor injection. // should eventually be replaced with constructor injection.
......
...@@ -4,8 +4,12 @@ ...@@ -4,8 +4,12 @@
package org.chromium.chrome.browser.dependency_injection; package org.chromium.chrome.browser.dependency_injection;
import static org.chromium.chrome.browser.dependency_injection.ChromeCommonQualifiers.APP_CONTEXT;
import static org.chromium.chrome.browser.dependency_injection.ChromeCommonQualifiers.LAST_USED_PROFILE; import static org.chromium.chrome.browser.dependency_injection.ChromeCommonQualifiers.LAST_USED_PROFILE;
import android.content.Context;
import org.chromium.base.ContextUtils;
import org.chromium.chrome.browser.contextual_suggestions.EnabledStateMonitor; import org.chromium.chrome.browser.contextual_suggestions.EnabledStateMonitor;
import org.chromium.chrome.browser.contextual_suggestions.EnabledStateMonitorImpl; import org.chromium.chrome.browser.contextual_suggestions.EnabledStateMonitorImpl;
import org.chromium.chrome.browser.preferences.ChromePreferenceManager; import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
...@@ -41,4 +45,10 @@ public class ChromeAppModule { ...@@ -41,4 +45,10 @@ public class ChromeAppModule {
public ChromePreferenceManager providesChromePreferenceManager() { public ChromePreferenceManager providesChromePreferenceManager() {
return ChromePreferenceManager.getInstance(); return ChromePreferenceManager.getInstance();
} }
@Provides
@Named(APP_CONTEXT)
public Context provideContext() {
return ContextUtils.getApplicationContext();
}
} }
...@@ -10,4 +10,7 @@ package org.chromium.chrome.browser.dependency_injection; ...@@ -10,4 +10,7 @@ package org.chromium.chrome.browser.dependency_injection;
*/ */
public interface ChromeCommonQualifiers { public interface ChromeCommonQualifiers {
String LAST_USED_PROFILE = "LAST_USED_PROFILE"; String LAST_USED_PROFILE = "LAST_USED_PROFILE";
String ACTIVITY_CONTEXT = "ACTIVITY_CONTEXT";
String APP_CONTEXT = "APP_CONTEXT";
} }
...@@ -53,7 +53,7 @@ public class ChromeFullscreenManager ...@@ -53,7 +53,7 @@ public class ChromeFullscreenManager
private final boolean mExitFullscreenOnStop; private final boolean mExitFullscreenOnStop;
private final TokenHolder mHidingTokenHolder = new TokenHolder(this::scheduleVisibilityUpdate); private final TokenHolder mHidingTokenHolder = new TokenHolder(this::scheduleVisibilityUpdate);
private ControlContainer mControlContainer; @Nullable private ControlContainer mControlContainer;
private int mTopControlContainerHeight; private int mTopControlContainerHeight;
private int mBottomControlContainerHeight; private int mBottomControlContainerHeight;
private boolean mControlsResizeView; private boolean mControlsResizeView;
...@@ -225,6 +225,7 @@ public class ChromeFullscreenManager ...@@ -225,6 +225,7 @@ public class ChromeFullscreenManager
mRendererTopContentOffset = mTopControlContainerHeight; mRendererTopContentOffset = mTopControlContainerHeight;
updateControlOffset(); updateControlOffset();
scheduleVisibilityUpdate();
} }
/** /**
...@@ -398,8 +399,9 @@ public class ChromeFullscreenManager ...@@ -398,8 +399,9 @@ public class ChromeFullscreenManager
} }
/** /**
* @return The toolbar control container. * @return The toolbar control container, null until {@link #initialize} is called.
*/ */
@Nullable
public ControlContainer getControlContainer() { public ControlContainer getControlContainer() {
return mControlContainer; return mControlContainer;
} }
...@@ -486,6 +488,9 @@ public class ChromeFullscreenManager ...@@ -486,6 +488,9 @@ public class ChromeFullscreenManager
* animation, preventing message loop stalls due to untimely invalidation. * animation, preventing message loop stalls due to untimely invalidation.
*/ */
private void scheduleVisibilityUpdate() { private void scheduleVisibilityUpdate() {
if (mControlContainer == null) {
return;
}
final int desiredVisibility = shouldShowAndroidControls() ? View.VISIBLE : View.INVISIBLE; final int desiredVisibility = shouldShowAndroidControls() ? View.VISIBLE : View.INVISIBLE;
if (mControlContainer.getView().getVisibility() == desiredVisibility) return; if (mControlContainer.getView().getVisibility() == desiredVisibility) return;
mControlContainer.getView().removeCallbacks(mUpdateVisibilityRunnable); mControlContainer.getView().removeCallbacks(mUpdateVisibilityRunnable);
......
...@@ -26,6 +26,9 @@ import java.util.regex.Pattern; ...@@ -26,6 +26,9 @@ import java.util.regex.Pattern;
* Utilities for working with URIs (and URLs). These methods may be used in security-sensitive * Utilities for working with URIs (and URLs). These methods may be used in security-sensitive
* contexts (after all, origins are the security boundary on the web), and so the correctness bar * contexts (after all, origins are the security boundary on the web), and so the correctness bar
* must be high. * must be high.
*
* Use ShadowUrlUtilities to mock out native-dependent methods in tests.
* TODO(pshmakov): we probably should just make those methods non-static.
*/ */
public class UrlUtilities { public class UrlUtilities {
private static final String TAG = "UrlUtilities"; private static final String TAG = "UrlUtilities";
......
...@@ -14,6 +14,7 @@ chrome_java_sources = [ ...@@ -14,6 +14,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/ActivityTaskDescriptionIconGenerator.java", "java/src/org/chromium/chrome/browser/ActivityTaskDescriptionIconGenerator.java",
"java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java", "java/src/org/chromium/chrome/browser/AfterStartupTaskUtils.java",
"java/src/org/chromium/chrome/browser/AppHooks.java", "java/src/org/chromium/chrome/browser/AppHooks.java",
"java/src/org/chromium/chrome/browser/AppHooksModule.java",
"java/src/org/chromium/chrome/browser/AppIndexingUtil.java", "java/src/org/chromium/chrome/browser/AppIndexingUtil.java",
"java/src/org/chromium/chrome/browser/ApplicationInitialization.java", "java/src/org/chromium/chrome/browser/ApplicationInitialization.java",
"java/src/org/chromium/chrome/browser/ApplicationLifetime.java", "java/src/org/chromium/chrome/browser/ApplicationLifetime.java",
...@@ -385,6 +386,7 @@ chrome_java_sources = [ ...@@ -385,6 +386,7 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java", "java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java",
"java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java", "java/src/org/chromium/chrome/browser/customtabs/CustomTabAppMenuPropertiesDelegate.java",
"java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java", "java/src/org/chromium/chrome/browser/customtabs/CustomTabBottomBarDelegate.java",
"java/src/org/chromium/chrome/browser/customtabs/CustomTabBrowserControlsVisibilityDelegate.java",
"java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java", "java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java",
"java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java", "java/src/org/chromium/chrome/browser/customtabs/CustomTabIntentDataProvider.java",
"java/src/org/chromium/chrome/browser/customtabs/CustomTabNavigationEventObserver.java", "java/src/org/chromium/chrome/browser/customtabs/CustomTabNavigationEventObserver.java",
...@@ -411,6 +413,8 @@ chrome_java_sources = [ ...@@ -411,6 +413,8 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/customtabs/SeparateTaskCustomTabActivity9.java", "java/src/org/chromium/chrome/browser/customtabs/SeparateTaskCustomTabActivity9.java",
"java/src/org/chromium/chrome/browser/customtabs/SeparateTaskManagedCustomTabActivity.java", "java/src/org/chromium/chrome/browser/customtabs/SeparateTaskManagedCustomTabActivity.java",
"java/src/org/chromium/chrome/browser/customtabs/TabObserverRegistrar.java", "java/src/org/chromium/chrome/browser/customtabs/TabObserverRegistrar.java",
"java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityComponent.java",
"java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityModule.java",
"java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityDelegate.java", "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityDelegate.java",
"java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java", "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ActivityHostImpl.java",
"java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleEntryPoint.java", "java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/ModuleEntryPoint.java",
...@@ -425,7 +429,6 @@ chrome_java_sources = [ ...@@ -425,7 +429,6 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/dependency_injection/ChromeAppComponent.java", "java/src/org/chromium/chrome/browser/dependency_injection/ChromeAppComponent.java",
"java/src/org/chromium/chrome/browser/dependency_injection/ChromeAppModule.java", "java/src/org/chromium/chrome/browser/dependency_injection/ChromeAppModule.java",
"java/src/org/chromium/chrome/browser/dependency_injection/ChromeCommonQualifiers.java", "java/src/org/chromium/chrome/browser/dependency_injection/ChromeCommonQualifiers.java",
"java/src/org/chromium/chrome/browser/dependency_injection/CustomTabActivityComponent.java",
"java/src/org/chromium/chrome/browser/dependency_injection/ModuleFactoryOverrides.java", "java/src/org/chromium/chrome/browser/dependency_injection/ModuleFactoryOverrides.java",
"java/src/org/chromium/chrome/browser/device/DeviceClassManager.java", "java/src/org/chromium/chrome/browser/device/DeviceClassManager.java",
"java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutController.java", "java/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutController.java",
......
...@@ -10,12 +10,16 @@ import static org.mockito.ArgumentMatchers.anyString; ...@@ -10,12 +10,16 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
...@@ -25,35 +29,29 @@ import org.robolectric.annotation.Config; ...@@ -25,35 +29,29 @@ import org.robolectric.annotation.Config;
import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.util.test.ShadowUrlUtilities;
/** /**
* Tests for {@link ClientAppDataRecorder}. * Tests for {@link ClientAppDataRecorder}.
*/ */
@RunWith(BaseRobolectricTestRunner.class) @RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE) @Config(manifest = Config.NONE, shadows = {ShadowUrlUtilities.class})
public class ClientAppDataRecorderTest { public class ClientAppDataRecorderTest {
private static final int APP_UID = 123; private static final int APP_UID = 123;
private static final String APP_NAME = "Example App"; private static final String APP_NAME = "Example App";
private static final String APP_PACKAGE = "com.example.app"; private static final String APP_PACKAGE = "com.example.app";
private static final String MISSING_PACKAGE = "com.missing.app"; private static final String MISSING_PACKAGE = "com.missing.app";
private static final Origin ORIGIN = new Origin("https://www.example.com/"); private static final Origin ORIGIN = new Origin("https://www.example.com/");
private static final Origin OTHER_ORIGIN = new Origin("https://www.example.com/"); private static final Origin OTHER_ORIGIN = new Origin("https://www.other.com/");
@Mock public ClientAppDataRegister mRegister; @Mock private ClientAppDataRegister mRegister;
@Mock public PackageManager mPackageManager; @Mock private PackageManager mPackageManager;
private ClientAppDataRecorder mRecorder; private ClientAppDataRecorder mRecorder;
private final ClientAppDataRecorder.UrlTransformer mUrlTransformer =
new ClientAppDataRecorder.UrlTransformer() { private static String transform(String origin) {
@Override
String getDomain(Origin origin) {
return transform(origin);
}
};
private static String transform(Origin origin) {
// Just an arbitrary string transformation so we can check it is applied. // Just an arbitrary string transformation so we can check it is applied.
return origin.toString().toUpperCase(); return origin.toUpperCase();
} }
@Before @Before
...@@ -72,7 +70,22 @@ public class ClientAppDataRecorderTest { ...@@ -72,7 +70,22 @@ public class ClientAppDataRecorderTest {
.when(mPackageManager) .when(mPackageManager)
.getApplicationInfo(eq(MISSING_PACKAGE), anyInt()); .getApplicationInfo(eq(MISSING_PACKAGE), anyInt());
mRecorder = new ClientAppDataRecorder(mPackageManager, mRegister, mUrlTransformer); Context context = mock(Context.class);
when(context.getPackageManager()).thenReturn(mPackageManager);
ShadowUrlUtilities.setTestImpl(new ShadowUrlUtilities.TestImpl() {
@Override
public String getDomainAndRegistry(String uri, boolean includePrivateRegistries) {
return transform(uri);
}
});
mRecorder = new ClientAppDataRecorder(context, mRegister);
}
@After
public void tearDown() {
ShadowUrlUtilities.reset();
} }
...@@ -80,7 +93,7 @@ public class ClientAppDataRecorderTest { ...@@ -80,7 +93,7 @@ public class ClientAppDataRecorderTest {
@Feature("TrustedWebActivities") @Feature("TrustedWebActivities")
public void testRegister() { public void testRegister() {
mRecorder.register(APP_PACKAGE, ORIGIN); mRecorder.register(APP_PACKAGE, ORIGIN);
verify(mRegister).registerPackageForDomain(APP_UID, APP_NAME, transform(ORIGIN)); verify(mRegister).registerPackageForDomain(APP_UID, APP_NAME, transform(ORIGIN.toString()));
} }
@Test @Test
...@@ -88,7 +101,7 @@ public class ClientAppDataRecorderTest { ...@@ -88,7 +101,7 @@ public class ClientAppDataRecorderTest {
public void testDeduplicate() { public void testDeduplicate() {
mRecorder.register(APP_PACKAGE, ORIGIN); mRecorder.register(APP_PACKAGE, ORIGIN);
mRecorder.register(APP_PACKAGE, ORIGIN); mRecorder.register(APP_PACKAGE, ORIGIN);
verify(mRegister).registerPackageForDomain(APP_UID, APP_NAME, transform(ORIGIN)); verify(mRegister).registerPackageForDomain(APP_UID, APP_NAME, transform(ORIGIN.toString()));
} }
@Test @Test
...@@ -96,9 +109,9 @@ public class ClientAppDataRecorderTest { ...@@ -96,9 +109,9 @@ public class ClientAppDataRecorderTest {
public void testDifferentOrigins() { public void testDifferentOrigins() {
mRecorder.register(APP_PACKAGE, ORIGIN); mRecorder.register(APP_PACKAGE, ORIGIN);
mRecorder.register(APP_PACKAGE, OTHER_ORIGIN); mRecorder.register(APP_PACKAGE, OTHER_ORIGIN);
verify(mRegister).registerPackageForDomain(APP_UID, APP_NAME, transform(ORIGIN)); verify(mRegister).registerPackageForDomain(APP_UID, APP_NAME, transform(ORIGIN.toString()));
verify(mRegister).registerPackageForDomain( verify(mRegister).registerPackageForDomain(
APP_UID, APP_NAME, transform(OTHER_ORIGIN)); APP_UID, APP_NAME, transform(OTHER_ORIGIN.toString()));
} }
@Test @Test
......
...@@ -30,11 +30,14 @@ import org.chromium.chrome.browser.util.test.ShadowUrlUtilities; ...@@ -30,11 +30,14 @@ import org.chromium.chrome.browser.util.test.ShadowUrlUtilities;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/** Tests for {@link DomainDataCleaner}. */ /** Tests for {@link DomainDataCleaner}. */
@RunWith(BaseRobolectricTestRunner.class) @RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE, shadows = {ShadowUrlUtilities.class}) @Config(manifest = Config.NONE, shadows = {ShadowUrlUtilities.class})
public class DomainDataCleanerTest { public class DomainDataCleanerTest {
private final Map<String, String> mUrlToDomain = new HashMap<>();
@Mock @Mock
private ChromeBrowserInitializer mChromeBrowserInitializer; private ChromeBrowserInitializer mChromeBrowserInitializer;
@Mock @Mock
...@@ -64,6 +67,13 @@ public class DomainDataCleanerTest { ...@@ -64,6 +67,13 @@ public class DomainDataCleanerTest {
return null; return null;
}).when(mWebsitePermissionsFetcher).fetchAllPreferences(any()); }).when(mWebsitePermissionsFetcher).fetchAllPreferences(any());
ShadowUrlUtilities.setTestImpl(new ShadowUrlUtilities.TestImpl() {
@Override
public String getDomainAndRegistry(String url, boolean includePrivateRegistries) {
return mUrlToDomain.get(url);
}
});
mCleaner = new DomainDataCleaner( mCleaner = new DomainDataCleaner(
mChromeBrowserInitializer, mSiteDataCleaner, mWebsitePermissionsFetcher); mChromeBrowserInitializer, mSiteDataCleaner, mWebsitePermissionsFetcher);
} }
...@@ -104,9 +114,9 @@ public class DomainDataCleanerTest { ...@@ -104,9 +114,9 @@ public class DomainDataCleanerTest {
verify(mFinishCallback).run(); verify(mFinishCallback).run();
} }
private Website makeMockWebsite(String origin, String domainAndRegistry) { private Website makeMockWebsite(String origin, String domain) {
Website website = new Website(WebsiteAddress.create(origin), null); Website website = new Website(WebsiteAddress.create(origin), null);
ShadowUrlUtilities.setUrlToToDomainMapping(origin, domainAndRegistry); mUrlToDomain.put(origin, domain);
return website; return website;
} }
......
...@@ -48,14 +48,15 @@ public class TrustedWebActivityDisclosureTest { ...@@ -48,14 +48,15 @@ public class TrustedWebActivityDisclosureTest {
doReturn("any string").when(mResources).getString(anyInt()); doReturn("any string").when(mResources).getString(anyInt());
doReturn(false).when(mPreferences).hasUserAcceptedTwaDisclosureForPackage(anyString()); doReturn(false).when(mPreferences).hasUserAcceptedTwaDisclosureForPackage(anyString());
mDisclosure = new TrustedWebActivityDisclosure(mResources, mPreferences); mDisclosure = new TrustedWebActivityDisclosure(mResources, mPreferences,
() -> mSnackbarManager);
} }
@Test @Test
@Feature("TrustedWebActivities") @Feature("TrustedWebActivities")
public void showIsIdempotent() { public void showIsIdempotent() {
mDisclosure.showSnackbarIfNeeded(mSnackbarManager, TWA_PACKAGE); mDisclosure.showIfNeeded(TWA_PACKAGE);
mDisclosure.showSnackbarIfNeeded(mSnackbarManager, TWA_PACKAGE); mDisclosure.showIfNeeded(TWA_PACKAGE);
verify(mSnackbarManager).showSnackbar(any()); verify(mSnackbarManager).showSnackbar(any());
} }
...@@ -63,10 +64,10 @@ public class TrustedWebActivityDisclosureTest { ...@@ -63,10 +64,10 @@ public class TrustedWebActivityDisclosureTest {
@Test @Test
@Feature("TrustedWebActivities") @Feature("TrustedWebActivities")
public void hideIsIdempotent() { public void hideIsIdempotent() {
mDisclosure.showSnackbarIfNeeded(mSnackbarManager, TWA_PACKAGE); mDisclosure.showIfNeeded(TWA_PACKAGE);
mDisclosure.dismissSnackbarIfNeeded(mSnackbarManager); mDisclosure.dismiss();
mDisclosure.dismissSnackbarIfNeeded(mSnackbarManager); mDisclosure.dismiss();
verify(mSnackbarManager).dismissSnackbars(any()); verify(mSnackbarManager).dismissSnackbars(any());
} }
...@@ -76,7 +77,7 @@ public class TrustedWebActivityDisclosureTest { ...@@ -76,7 +77,7 @@ public class TrustedWebActivityDisclosureTest {
public void noShowIfAlreadyAccepted() { public void noShowIfAlreadyAccepted() {
doReturn(true).when(mPreferences).hasUserAcceptedTwaDisclosureForPackage(anyString()); doReturn(true).when(mPreferences).hasUserAcceptedTwaDisclosureForPackage(anyString());
mDisclosure.showSnackbarIfNeeded(mSnackbarManager, TWA_PACKAGE); mDisclosure.showIfNeeded(TWA_PACKAGE);
verify(mSnackbarManager, times(0)).showSnackbar(any()); verify(mSnackbarManager, times(0)).showSnackbar(any());
} }
...@@ -85,7 +86,7 @@ public class TrustedWebActivityDisclosureTest { ...@@ -85,7 +86,7 @@ public class TrustedWebActivityDisclosureTest {
@Feature("TrustedWebActivities") @Feature("TrustedWebActivities")
public void recordDismiss() { public void recordDismiss() {
ArgumentCaptor<Snackbar> snackbarCaptor = ArgumentCaptor.forClass(Snackbar.class); ArgumentCaptor<Snackbar> snackbarCaptor = ArgumentCaptor.forClass(Snackbar.class);
mDisclosure.showSnackbarIfNeeded(mSnackbarManager, TWA_PACKAGE); mDisclosure.showIfNeeded(TWA_PACKAGE);
verify(mSnackbarManager).showSnackbar(snackbarCaptor.capture()); verify(mSnackbarManager).showSnackbar(snackbarCaptor.capture());
...@@ -101,7 +102,7 @@ public class TrustedWebActivityDisclosureTest { ...@@ -101,7 +102,7 @@ public class TrustedWebActivityDisclosureTest {
@Feature("TrustedWebActivities") @Feature("TrustedWebActivities")
public void doNothingOnNoSnackbarAction() { public void doNothingOnNoSnackbarAction() {
ArgumentCaptor<Snackbar> snackbarCaptor = ArgumentCaptor.forClass(Snackbar.class); ArgumentCaptor<Snackbar> snackbarCaptor = ArgumentCaptor.forClass(Snackbar.class);
mDisclosure.showSnackbarIfNeeded(mSnackbarManager, TWA_PACKAGE); mDisclosure.showIfNeeded(TWA_PACKAGE);
verify(mSnackbarManager).showSnackbar(snackbarCaptor.capture()); verify(mSnackbarManager).showSnackbar(snackbarCaptor.capture());
......
...@@ -8,35 +8,44 @@ import android.text.TextUtils; ...@@ -8,35 +8,44 @@ import android.text.TextUtils;
import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements; import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import org.chromium.chrome.browser.util.UrlUtilities; import org.chromium.chrome.browser.util.UrlUtilities;
import java.util.HashMap;
import java.util.Map;
/** Implementation of UrlUtilities which does not rely on native. */ /** Implementation of UrlUtilities which does not rely on native. */
@Implements(UrlUtilities.class) @Implements(UrlUtilities.class)
public class ShadowUrlUtilities { public class ShadowUrlUtilities {
private static Map<String, String> sUrlToToDomain = new HashMap<>();
private static TestImpl sTestImpl = new TestImpl();
/** Set implementation for tests. Don't forget to call {@link #reset} later. */
public static void setTestImpl(TestImpl impl) {
sTestImpl = impl;
}
@Resetter
public static void reset() {
sTestImpl = new TestImpl();
}
@Implementation @Implementation
public static boolean urlsMatchIgnoringFragments(String url, String url2) { public static boolean urlsMatchIgnoringFragments(String url, String url2) {
return TextUtils.equals(url, url2); return sTestImpl.urlsMatchIgnoringFragments(url, url2);
} }
@Implementation @Implementation
public static String getDomainAndRegistry(String url, boolean includePrivateRegistries) { public static String getDomainAndRegistry(String uri, boolean includePrivateRegistries) {
String domain = sUrlToToDomain.get(url); return sTestImpl.getDomainAndRegistry(uri, includePrivateRegistries);
return domain == null ? url : domain;
} }
/** Add a url to domain mapping. */ /** Default implementation for tests. Override methods or add new ones as necessary. */
public static void setUrlToToDomainMapping(String url, String domain) { public static class TestImpl {
sUrlToToDomain.put(url, domain); public boolean urlsMatchIgnoringFragments(String url, String url2) {
} return TextUtils.equals(url, url2);
}
/** Clear the static state. */ public String getDomainAndRegistry(String uri, boolean includePrivateRegistries) {
public static void reset() { return uri;
sUrlToToDomain.clear(); }
} }
} }
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