Commit d49d113d authored by Robbie McElrath's avatar Robbie McElrath Committed by Chromium LUCI CQ

[WebLayer] Rename Site Settings files to just Settings

This CL renames most of WebLayer's Site Settings files to just Settings
in preparation of introducing more Settings UIs.

This introduces a new ISettingsFragment rather than renaming
ISiteSettingsFragment because renaming the interface results in a
"SecurityException: Binder invocation to an incorrect interface"
exception when launching Site Settings.

Bug: 1106393
Change-Id: Ifbeb15a8ff51776a901e0136dfbdcb4b19543a39
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2572689
Commit-Queue: Robbie McElrath <rmcelrath@chromium.org>
Reviewed-by: default avatarBo <boliu@chromium.org>
Reviewed-by: default avatarScott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#834358}
parent d3fa12a7
......@@ -147,7 +147,7 @@ android_library("weblayer_java_private_test_support") {
testonly = true
sources = [
"src/org/chromium/weblayer/test/BrowserControlsHelper.java",
"src/org/chromium/weblayer/test/SiteSettingsActivityTestRule.java",
"src/org/chromium/weblayer/test/SettingsActivityTestRule.java",
]
deps = [
":weblayer_java_test_support",
......
......@@ -9,52 +9,34 @@ import android.content.Intent;
import android.support.test.InstrumentationRegistry;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.weblayer.SiteSettingsActivity;
import org.chromium.weblayer.SiteSettingsTestUtils;
import org.chromium.weblayer.SettingsActivity;
import org.chromium.weblayer.WebLayer;
/**
* ActivityTestRule for SiteSettingsActivity.
* ActivityTestRule for SettingsActivity.
*
* Test can use this ActivityTestRule to launch SiteSettingsActivity.
* Test can use this ActivityTestRule to launch SettingsActivity.
*/
public class SiteSettingsActivityTestRule extends WebLayerActivityTestRule<SiteSettingsActivity> {
public class SettingsActivityTestRule extends WebLayerActivityTestRule<SettingsActivity> {
private Context mAppContext;
public SiteSettingsActivityTestRule() {
super(SiteSettingsActivity.class);
public SettingsActivityTestRule() {
super(SettingsActivity.class);
}
public SiteSettingsActivity launchCategoryListWithProfile(String profileName) {
Intent siteSettingsIntent = TestThreadUtils.runOnUiThreadBlockingNoException(() -> {
@Override
public void launchActivity(Intent settingsIntent) {
TestThreadUtils.runOnUiThreadBlocking(() -> {
// We load WebLayer here so it gets initialized with the test/instrumentation Context,
// which has an in-memory SharedPreferences. Without this call, WebLayer gets
// initialized with the Application as its appContext, which breaks tests because a
// SharedPreferences xml file is persisted to disk.
WebLayer.loadSync(getContext());
return SiteSettingsActivity.createIntentForCategoryList(
getContext(), profileName, "".equals(profileName));
});
launchActivity(siteSettingsIntent);
return getActivity();
super.launchActivity(settingsIntent);
}
public SiteSettingsActivity launchSingleSiteSettingsWithProfile(
String profileName, String url) {
Intent siteSettingsIntent = TestThreadUtils.runOnUiThreadBlockingNoException(() -> {
// We load WebLayer here so it gets initialized with the test/instrumentation Context,
// which has an in-memory SharedPreferences. Without this call, WebLayer gets
// initialized with the Application as its appContext, which breaks tests because a
// SharedPreferences xml file is persisted to disk.
WebLayer.loadSync(getContext());
return SiteSettingsTestUtils.createIntentForSingleWebsite(
getContext(), profileName, "".equals(profileName), url);
});
launchActivity(siteSettingsIntent);
return getActivity();
}
private Context getContext() {
public Context getContext() {
if (mAppContext == null) {
mAppContext = InstrumentationRegistry.getInstrumentation()
.getTargetContext()
......
......@@ -29,6 +29,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.weblayer.SettingsTestUtils;
import org.chromium.weblayer.SiteSettingsActivity;
/**
* Tests the behavior of the Site Settings UI.
......@@ -41,13 +43,15 @@ public class SiteSettingsTest {
private static final String PROFILE_NAME = "DefaultProfile";
@Rule
public SiteSettingsActivityTestRule mSiteSettingsTestRule = new SiteSettingsActivityTestRule();
public SettingsActivityTestRule mSettingsTestRule = new SettingsActivityTestRule();
@Test
@SmallTest
@MinWebLayerVersion(84)
public void testSiteSettingsLaunches() throws InterruptedException {
mSiteSettingsTestRule.launchCategoryListWithProfile(PROFILE_NAME);
mSettingsTestRule.launchActivity(
SiteSettingsActivity.createIntentForSiteSettingsCategoryList(
mSettingsTestRule.getContext(), PROFILE_NAME, /*isIncognito=*/false));
onView(withText("All sites")).check(matches(isDisplayed()));
}
......@@ -56,7 +60,9 @@ public class SiteSettingsTest {
@SmallTest
@MinWebLayerVersion(84)
public void testAllSitesLaunches() throws InterruptedException {
mSiteSettingsTestRule.launchCategoryListWithProfile(PROFILE_NAME);
mSettingsTestRule.launchActivity(
SiteSettingsActivity.createIntentForSiteSettingsCategoryList(
mSettingsTestRule.getContext(), PROFILE_NAME, /*isIncognito=*/false));
onView(withText("All sites")).perform(click());
......@@ -68,7 +74,9 @@ public class SiteSettingsTest {
@SmallTest
@MinWebLayerVersion(84)
public void testJavascriptExceptionPopupLaunches() throws InterruptedException {
mSiteSettingsTestRule.launchCategoryListWithProfile(PROFILE_NAME);
mSettingsTestRule.launchActivity(
SiteSettingsActivity.createIntentForSiteSettingsCategoryList(
mSettingsTestRule.getContext(), PROFILE_NAME, /*isIncognito=*/false));
onView(withText("JavaScript")).perform(click());
onView(withText("Add site exception")).perform(click());
......@@ -81,7 +89,8 @@ public class SiteSettingsTest {
@MinWebLayerVersion(84)
@DisabledTest(message = "TODO(crbug.com/1150676): Fix flakiness.")
public void testSingleSiteSoundPopupLaunches() throws InterruptedException {
mSiteSettingsTestRule.launchSingleSiteSettingsWithProfile(PROFILE_NAME, GOOGLE_URL);
mSettingsTestRule.launchActivity(SettingsTestUtils.createIntentForSiteSettingsSingleWebsite(
mSettingsTestRule.getContext(), PROFILE_NAME, /*isIncognito=*/false, GOOGLE_URL));
onView(withText("Sound")).perform(click());
......@@ -93,7 +102,8 @@ public class SiteSettingsTest {
@MinWebLayerVersion(84)
@DisabledTest(message = "TODO(crbug.com/1150676): Fix flakiness.")
public void testSingleSiteClearPopupLaunches() throws InterruptedException {
mSiteSettingsTestRule.launchSingleSiteSettingsWithProfile(PROFILE_NAME, GOOGLE_URL);
mSettingsTestRule.launchActivity(SettingsTestUtils.createIntentForSiteSettingsSingleWebsite(
mSettingsTestRule.getContext(), PROFILE_NAME, /*isIncognito=*/false, GOOGLE_URL));
onView(withText("Clear & reset")).perform(click());
......@@ -108,9 +118,12 @@ public class SiteSettingsTest {
public void testSingleSiteLocationAccess() throws InterruptedException {
try {
Intents.init();
mSiteSettingsTestRule.launchSingleSiteSettingsWithProfile(PROFILE_NAME, GOOGLE_URL);
mSettingsTestRule.launchActivity(
SettingsTestUtils.createIntentForSiteSettingsSingleWebsite(
mSettingsTestRule.getContext(), PROFILE_NAME, /*isIncognito=*/false,
GOOGLE_URL));
onView(withText("Location access")).perform(click());
onView(withText("Location")).perform(click());
Matcher<Intent> settingsMatcher =
IntentMatchers.hasAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
......
......@@ -25,7 +25,7 @@ android_resources("weblayer_resources") {
"res/drawable-xxhdpi/amp_icon.png",
"res/drawable-xxxhdpi/amp_icon.png",
"res/drawable/weblayer_tab_indicator.xml",
"res/layout/site_settings_layout.xml",
"res/layout/settings_layout.xml",
"res/layout/weblayer_infobar_translate_compact_content.xml",
"res/layout/weblayer_url_bar.xml",
"res/values/colors.xml",
......@@ -143,7 +143,6 @@ android_library("java") {
"org/chromium/weblayer_private/ProfileImpl.java",
"org/chromium/weblayer_private/ProfileManager.java",
"org/chromium/weblayer_private/RemoteFragmentImpl.java",
"org/chromium/weblayer_private/SiteSettingsFragmentImpl.java",
"org/chromium/weblayer_private/TabCallbackProxy.java",
"org/chromium/weblayer_private/TabImpl.java",
"org/chromium/weblayer_private/TranslateCompactInfoBar.java",
......@@ -155,7 +154,6 @@ android_library("java") {
"org/chromium/weblayer_private/WebLayerImpl.java",
"org/chromium/weblayer_private/WebLayerNotificationChannels.java",
"org/chromium/weblayer_private/WebLayerNotificationWrapperBuilder.java",
"org/chromium/weblayer_private/WebLayerSiteSettingsClient.java",
"org/chromium/weblayer_private/WebLayerTabModalPresenter.java",
"org/chromium/weblayer_private/WebMessageReplyProxyImpl.java",
"org/chromium/weblayer_private/WebShareServiceFactory.java",
......@@ -170,6 +168,8 @@ android_library("java") {
"org/chromium/weblayer_private/payments/WebLayerPaymentRequestService.java",
"org/chromium/weblayer_private/permissions/PermissionRequestUtils.java",
"org/chromium/weblayer_private/resources/ResourceMapper.java",
"org/chromium/weblayer_private/settings/SettingsFragmentImpl.java",
"org/chromium/weblayer_private/settings/WebLayerSiteSettingsClient.java",
_bundle_utils_output,
]
resources_package = "org.chromium.weblayer_private"
......@@ -396,8 +396,8 @@ android_library("interfaces_java") {
"org/chromium/weblayer_private/interfaces/RemoteMediaServiceConstants.java",
"org/chromium/weblayer_private/interfaces/ScrollNotificationType.java",
"org/chromium/weblayer_private/interfaces/SettingType.java",
"org/chromium/weblayer_private/interfaces/SiteSettingsFragmentArgs.java",
"org/chromium/weblayer_private/interfaces/SiteSettingsIntentHelper.java",
"org/chromium/weblayer_private/interfaces/SettingsFragmentArgs.java",
"org/chromium/weblayer_private/interfaces/SettingsIntentHelper.java",
"org/chromium/weblayer_private/interfaces/StrictModeWorkaround.java",
"org/chromium/weblayer_private/interfaces/UrlBarOptionsKeys.java",
"org/chromium/weblayer_private/interfaces/WebLayerVersionConstants.java",
......@@ -466,6 +466,7 @@ android_aidl("aidl") {
"org/chromium/weblayer_private/interfaces/IProfileClient.aidl",
"org/chromium/weblayer_private/interfaces/IRemoteFragment.aidl",
"org/chromium/weblayer_private/interfaces/IRemoteFragmentClient.aidl",
"org/chromium/weblayer_private/interfaces/ISettingsFragment.aidl",
"org/chromium/weblayer_private/interfaces/ISiteSettingsFragment.aidl",
"org/chromium/weblayer_private/interfaces/ITab.aidl",
"org/chromium/weblayer_private/interfaces/ITabClient.aidl",
......
......@@ -30,7 +30,8 @@ import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.url.GURL;
import org.chromium.weblayer_private.interfaces.ObjectWrapper;
import org.chromium.weblayer_private.interfaces.SiteSettingsIntentHelper;
import org.chromium.weblayer_private.interfaces.SettingsIntentHelper;
import org.chromium.weblayer_private.settings.WebLayerSiteSettingsClient;
/**
* WebLayer's customization of PageInfoControllerDelegate.
......@@ -65,7 +66,7 @@ public class PageInfoControllerDelegateImpl extends PageInfoControllerDelegate {
*/
@Override
public void showSiteSettings(String url) {
Intent intent = SiteSettingsIntentHelper.createIntentForSingleWebsite(
Intent intent = SettingsIntentHelper.createIntentForSiteSettingsSingleWebsite(
mContext, mProfile.getName(), mProfile.isIncognito(), url);
// Disabling StrictMode to avoid violations (https://crbug.com/819410).
......@@ -77,7 +78,7 @@ public class PageInfoControllerDelegateImpl extends PageInfoControllerDelegate {
String category = SiteSettingsCategory.preferenceKey(SiteSettingsCategory.Type.COOKIES);
String title = mContext.getResources().getString(
ContentSettingsResources.getTitle(ContentSettingsType.COOKIES));
Intent intent = SiteSettingsIntentHelper.createIntentForSingleCategory(
Intent intent = SettingsIntentHelper.createIntentForSiteSettingsSingleCategory(
mContext, mProfile.getName(), mProfile.isIncognito(), category, title);
launchIntent(intent);
}
......
......@@ -72,6 +72,7 @@ import org.chromium.weblayer_private.interfaces.IMediaRouteDialogFragment;
import org.chromium.weblayer_private.interfaces.IObjectWrapper;
import org.chromium.weblayer_private.interfaces.IProfile;
import org.chromium.weblayer_private.interfaces.IRemoteFragmentClient;
import org.chromium.weblayer_private.interfaces.ISettingsFragment;
import org.chromium.weblayer_private.interfaces.ISiteSettingsFragment;
import org.chromium.weblayer_private.interfaces.IWebLayer;
import org.chromium.weblayer_private.interfaces.IWebLayerClient;
......@@ -83,6 +84,7 @@ import org.chromium.weblayer_private.media.MediaSessionManager;
import org.chromium.weblayer_private.media.MediaStreamManager;
import org.chromium.weblayer_private.metrics.MetricsServiceClient;
import org.chromium.weblayer_private.metrics.UmaUtils;
import org.chromium.weblayer_private.settings.SettingsFragmentImpl;
import java.io.File;
import java.lang.reflect.Constructor;
......@@ -330,14 +332,22 @@ public final class WebLayerImpl extends IWebLayer.Stub {
return fragment.asIBrowserFragment();
}
@Override
public ISettingsFragment createSettingsFragmentImpl(
IRemoteFragmentClient remoteFragmentClient, IObjectWrapper fragmentArgs) {
StrictModeWorkaround.apply();
Bundle unwrappedArgs = ObjectWrapper.unwrap(fragmentArgs, Bundle.class);
return new SettingsFragmentImpl(mProfileManager, remoteFragmentClient, unwrappedArgs)
.asISettingsFragment();
}
@Override
public ISiteSettingsFragment createSiteSettingsFragmentImpl(
IRemoteFragmentClient remoteFragmentClient, IObjectWrapper fragmentArgs) {
StrictModeWorkaround.apply();
Bundle unwrappedArgs = ObjectWrapper.unwrap(fragmentArgs, Bundle.class);
SiteSettingsFragmentImpl fragment =
new SiteSettingsFragmentImpl(mProfileManager, remoteFragmentClient, unwrappedArgs);
return fragment.asISiteSettingsFragment();
return new SettingsFragmentImpl(mProfileManager, remoteFragmentClient, unwrappedArgs)
.asISiteSettingsFragment();
}
@Override
......
// Copyright 2020 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.weblayer_private.interfaces;
import org.chromium.weblayer_private.interfaces.IRemoteFragment;
interface ISettingsFragment {
IRemoteFragment asRemoteFragment() = 0;
}
......@@ -13,6 +13,7 @@ import org.chromium.weblayer_private.interfaces.IObjectWrapper;
import org.chromium.weblayer_private.interfaces.IProfile;
import org.chromium.weblayer_private.interfaces.IRemoteFragmentClient;
import org.chromium.weblayer_private.interfaces.IMediaRouteDialogFragment;
import org.chromium.weblayer_private.interfaces.ISettingsFragment;
import org.chromium.weblayer_private.interfaces.ISiteSettingsFragment;
import org.chromium.weblayer_private.interfaces.IWebLayerClient;
......@@ -110,6 +111,17 @@ interface IWebLayer {
void onRemoteMediaServiceStarted(in IObjectWrapper sessionService, in Intent intent) = 22;
void onRemoteMediaServiceDestroyed(int id) = 23;
// Creates the WebLayer counterpart to a SettingsFragment - a SettingsFragmentImpl
//
// @param fragmentClient Representative of the Fragment on the client side through which
// WebLayer can call methods on Fragment.
// @param fragmentArgs Bundle of arguments with which the Fragment was created on the client side
// (see Fragment#setArguments).
// Added in Version 89.
ISettingsFragment createSettingsFragmentImpl(
in IRemoteFragmentClient remoteFragmentClient,
in IObjectWrapper fragmentArgs) = 25;
// WARNING: when choosing next value make sure you look back for the max, as
// merges may mean the last function does not have the max value.
}
......@@ -4,9 +4,9 @@
package org.chromium.weblayer_private.interfaces;
/** Keys for the Bundle of arguments with which SiteSettingsFragments are created. */
public interface SiteSettingsFragmentArgs {
String ACTIVITY_CLASS_NAME = "org.chromium.weblayer.SiteSettingsActivity";
/** Keys for the Bundle of arguments with which SettingsFragments are created. */
public interface SettingsFragmentArgs {
String ACTIVITY_CLASS_NAME = "org.chromium.weblayer.SettingsActivity";
// Argument names
String PROFILE_NAME = "profile_name";
......
......@@ -9,72 +9,68 @@ import android.content.Intent;
import android.os.Bundle;
/**
* A helper class for creating Intents to start the Site Settings UI.
* A helper class for creating Intents to start Settings UI Fragments.
*/
public class SiteSettingsIntentHelper {
private static Bundle createSiteSettingsExtras(String profileName, boolean isIncognito) {
public class SettingsIntentHelper {
private static Bundle createSettingsExtras(String profileName, boolean isIncognito) {
Bundle extras = new Bundle();
extras.putString(SiteSettingsFragmentArgs.PROFILE_NAME, profileName);
extras.putBoolean(SiteSettingsFragmentArgs.IS_INCOGNITO_PROFILE, isIncognito);
extras.putString(SettingsFragmentArgs.PROFILE_NAME, profileName);
extras.putBoolean(SettingsFragmentArgs.IS_INCOGNITO_PROFILE, isIncognito);
return extras;
}
/** Creates an Intent that launches the main category list UI. */
public static Intent createIntentForCategoryList(
public static Intent createIntentForSiteSettingsCategoryList(
Context context, String profileName, boolean isIncognito) {
Bundle extras = createSiteSettingsExtras(profileName, isIncognito);
extras.putString(
SiteSettingsFragmentArgs.FRAGMENT_NAME, SiteSettingsFragmentArgs.CATEGORY_LIST);
Bundle extras = createSettingsExtras(profileName, isIncognito);
extras.putString(SettingsFragmentArgs.FRAGMENT_NAME, SettingsFragmentArgs.CATEGORY_LIST);
return createIntentWithExtras(context, extras);
}
/** Creates an Intent that launches the settings UI for a single category. */
public static Intent createIntentForSingleCategory(Context context, String profileName,
boolean isIncognito, String categoryType, String categoryTitle) {
Bundle extras = createSiteSettingsExtras(profileName, isIncognito);
extras.putString(
SiteSettingsFragmentArgs.FRAGMENT_NAME, SiteSettingsFragmentArgs.SINGLE_CATEGORY);
public static Intent createIntentForSiteSettingsSingleCategory(Context context,
String profileName, boolean isIncognito, String categoryType, String categoryTitle) {
Bundle extras = createSettingsExtras(profileName, isIncognito);
extras.putString(SettingsFragmentArgs.FRAGMENT_NAME, SettingsFragmentArgs.SINGLE_CATEGORY);
Bundle fragmentArgs = new Bundle();
fragmentArgs.putString(SiteSettingsFragmentArgs.SINGLE_CATEGORY_TYPE, categoryType);
fragmentArgs.putString(SiteSettingsFragmentArgs.SINGLE_CATEGORY_TITLE, categoryTitle);
extras.putBundle(SiteSettingsFragmentArgs.FRAGMENT_ARGUMENTS, fragmentArgs);
fragmentArgs.putString(SettingsFragmentArgs.SINGLE_CATEGORY_TYPE, categoryType);
fragmentArgs.putString(SettingsFragmentArgs.SINGLE_CATEGORY_TITLE, categoryTitle);
extras.putBundle(SettingsFragmentArgs.FRAGMENT_ARGUMENTS, fragmentArgs);
return createIntentWithExtras(context, extras);
}
/** Creates an Intent that launches the single website settings UI. */
public static Intent createIntentForSingleWebsite(
public static Intent createIntentForSiteSettingsSingleWebsite(
Context context, String profileName, boolean isIncognito, String url) {
Bundle extras = createSiteSettingsExtras(profileName, isIncognito);
extras.putString(
SiteSettingsFragmentArgs.FRAGMENT_NAME, SiteSettingsFragmentArgs.SINGLE_WEBSITE);
Bundle extras = createSettingsExtras(profileName, isIncognito);
extras.putString(SettingsFragmentArgs.FRAGMENT_NAME, SettingsFragmentArgs.SINGLE_WEBSITE);
Bundle fragmentArgs = new Bundle();
fragmentArgs.putString(SiteSettingsFragmentArgs.SINGLE_WEBSITE_URL, url);
extras.putBundle(SiteSettingsFragmentArgs.FRAGMENT_ARGUMENTS, fragmentArgs);
fragmentArgs.putString(SettingsFragmentArgs.SINGLE_WEBSITE_URL, url);
extras.putBundle(SettingsFragmentArgs.FRAGMENT_ARGUMENTS, fragmentArgs);
return createIntentWithExtras(context, extras);
}
/** Creates an Intent that launches the all sites settings UI. */
public static Intent createIntentForAllSites(
public static Intent createIntentForSiteSettingsAllSites(
Context context, String profileName, boolean isIncognito, String type, String title) {
Bundle extras = createSiteSettingsExtras(profileName, isIncognito);
extras.putString(
SiteSettingsFragmentArgs.FRAGMENT_NAME, SiteSettingsFragmentArgs.ALL_SITES);
Bundle extras = createSettingsExtras(profileName, isIncognito);
extras.putString(SettingsFragmentArgs.FRAGMENT_NAME, SettingsFragmentArgs.ALL_SITES);
Bundle fragmentArgs = new Bundle();
fragmentArgs.putString(SiteSettingsFragmentArgs.ALL_SITES_TITLE, title);
fragmentArgs.putString(SiteSettingsFragmentArgs.ALL_SITES_TYPE, type);
extras.putBundle(SiteSettingsFragmentArgs.FRAGMENT_ARGUMENTS, fragmentArgs);
fragmentArgs.putString(SettingsFragmentArgs.ALL_SITES_TITLE, title);
fragmentArgs.putString(SettingsFragmentArgs.ALL_SITES_TYPE, type);
extras.putBundle(SettingsFragmentArgs.FRAGMENT_ARGUMENTS, fragmentArgs);
return createIntentWithExtras(context, extras);
}
private static Intent createIntentWithExtras(Context context, Bundle extras) {
Intent intent = new Intent();
intent.setClassName(context, SiteSettingsFragmentArgs.ACTIVITY_CLASS_NAME);
intent.setClassName(context, SettingsFragmentArgs.ACTIVITY_CLASS_NAME);
intent.putExtras(extras);
return intent;
}
private SiteSettingsIntentHelper() {}
private SettingsIntentHelper() {}
}
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.weblayer_private;
package org.chromium.weblayer_private.settings;
import android.app.Activity;
import android.graphics.Bitmap;
......@@ -21,6 +21,7 @@ import org.chromium.components.content_settings.ContentSettingsType;
import org.chromium.components.embedder_support.browser_context.BrowserContextHandle;
import org.chromium.components.embedder_support.util.Origin;
import org.chromium.components.page_info.PageInfoFeatureList;
import org.chromium.weblayer_private.WebLayerImpl;
import java.util.Collections;
import java.util.Set;
......
......@@ -10,7 +10,7 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/site_settings_container">
android:id="@+id/settings_container">
</FrameLayout>
<include layout="@layout/settings_action_bar_shadow" />
</RelativeLayout>
......@@ -4,7 +4,7 @@
found in the LICENSE file. -->
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="Theme.WebLayer.SiteSettings" parent="Theme.BrowserUI">
<style name="Theme.WebLayer.Settings" parent="Theme.BrowserUI">
<item name="preferenceTheme">@style/PreferenceTheme</item>
<item name="alertDialogTheme">@style/Theme.Chromium.AlertDialog</item>
......
......@@ -56,8 +56,13 @@
android:resource="@xml/weblayer_file_paths" />
</provider>
<activity android:name="org.chromium.weblayer.SettingsActivity"
android:theme="@style/Theme.WebLayer.Settings"
android:exported="false">
</activity>
<activity android:name="org.chromium.weblayer.SiteSettingsActivity"
android:theme="@style/Theme.WebLayer.SiteSettings"
android:theme="@style/Theme.WebLayer.Settings"
android:exported="false">
</activity>
......
......@@ -88,8 +88,9 @@ android_library("java") {
"org/chromium/weblayer/ScrollNotificationType.java",
"org/chromium/weblayer/ScrollOffsetCallback.java",
"org/chromium/weblayer/SettingType.java",
"org/chromium/weblayer/SettingsActivity.java",
"org/chromium/weblayer/SettingsFragment.java",
"org/chromium/weblayer/SiteSettingsActivity.java",
"org/chromium/weblayer/SiteSettingsFragment.java",
"org/chromium/weblayer/Tab.java",
"org/chromium/weblayer/TabCallback.java",
"org/chromium/weblayer/TabListCallback.java",
......
// Copyright 2020 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.weblayer;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.appcompat.app.AppCompatActivity;
import org.chromium.weblayer_private.interfaces.SettingsIntentHelper;
/**
* An Activity that displays a Settings UI for WebLayer.
*
* This class is an implementation detail. To start an instance of this Activity, use one of the
* SettingsActivity#createIntentFor* methods.
*
* @since 89
*/
public class SettingsActivity extends AppCompatActivity {
private static final String FRAGMENT_TAG = "settingsFragment";
/**
* Tracks whether we've checked that this Activity isn't exported.
*
* @see SettingsActivity#ensureActivityNotExported()
*/
private static boolean sActivityNotExportedChecked;
/** The current instance of SettingsActivity in the resumed state, if any. */
private static SettingsActivity sResumedInstance;
/** Whether this activity has been created for the first time but not yet resumed. */
private boolean mIsNewlyCreated;
/**
* Creates an Intent that will launch the root/full Site Settings UI, which displays a list of
* settings categories.
*
* @param profileName The name of the profile.
*
* @since 89
*/
public static Intent createIntentForSiteSettingsCategoryList(
Context context, String profileName) {
return SettingsIntentHelper.createIntentForSiteSettingsCategoryList(
context, profileName, "".equals(profileName));
}
/**
* Creates an Intent that will launch the root/full Site Settings UI, which displays a list of
* settings categories.
*
* @param profileName The name of the profile.
* @param isIncognito If the profile is incognito.
*
* @since 89
*/
public static Intent createIntentForSiteSettingsCategoryList(
Context context, String profileName, boolean isIncognito) {
return SettingsIntentHelper.createIntentForSiteSettingsCategoryList(
context, profileName, isIncognito);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
ensureActivityNotExported();
super.onCreate(savedInstanceState);
mIsNewlyCreated = savedInstanceState == null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setElevation(0);
if (getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG) == null) {
SettingsFragment settingsFragment = new SettingsFragment();
settingsFragment.setArguments(getIntent().getExtras());
getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, settingsFragment, FRAGMENT_TAG)
.commitNow();
}
}
@Override
protected void onResume() {
super.onResume();
// Prevent the user from interacting with multiple instances of SettingsActivity at the
// same time (e.g. in multi-instance mode on a Samsung device), which would cause many fun
// bugs.
if (sResumedInstance != null && sResumedInstance.getTaskId() != getTaskId()) {
if (mIsNewlyCreated) {
// This activity was newly created and takes precedence over sResumedInstance.
sResumedInstance.finish();
} else {
// This activity was unpaused or recreated while another instance of
// SettingsActivity was already showing. The existing instance takes precedence.
finish();
return;
}
}
sResumedInstance = this;
mIsNewlyCreated = false;
}
@Override
protected void onStop() {
super.onStop();
if (sResumedInstance == this) {
sResumedInstance = null;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Records that the Activity export check has occurred, and returns whether this method has been
* previously called or not.
*
* This method is overridden by subclasses to allow them to save their own static state, but
* should be removed and inlined into ensureActivityNotExported() once SiteSettingsActivity is
* removed (it was deprecated in M89).
*/
protected boolean markActivityExportChecked() {
boolean oldValue = sActivityNotExportedChecked;
sActivityNotExportedChecked = true;
return oldValue;
}
private void ensureActivityNotExported() {
if (markActivityExportChecked()) return;
try {
ActivityInfo activityInfo = getPackageManager().getActivityInfo(getComponentName(), 0);
// If SettingsActivity is exported, then it's vulnerable to a fragment injection
// exploit:
// http://securityintelligence.com/new-vulnerability-android-framework-fragment-injection
if (activityInfo.exported) {
throw new IllegalStateException("SettingsActivity must not be exported.");
}
} catch (NameNotFoundException ex) {
// Something terribly wrong has happened.
throw new RuntimeException(ex);
}
}
}
......@@ -10,13 +10,16 @@ import android.os.Bundle;
import org.chromium.weblayer_private.interfaces.IRemoteFragment;
/**
* The client-side implementation of a SiteSettingsFragment.
* The client-side implementation of a SettingsFragment.
*
* This is a Fragment that can be shown within an embedder's UI, and proxies its lifecycle events to
* a SiteSettingsFragmentImpl object on the implementation side.
* a SettingsFragmentImpl object on the implementation side. This class is an implementation detail
* and should not be used by an embedder directly.
*
* @since 89
*/
public class SiteSettingsFragment extends RemoteFragment {
public SiteSettingsFragment() {
public class SettingsFragment extends RemoteFragment {
public SettingsFragment() {
super();
}
......@@ -25,11 +28,17 @@ public class SiteSettingsFragment extends RemoteFragment {
try {
Bundle args = getArguments();
if (args == null) {
throw new RuntimeException("SiteSettingsFragment was created without arguments.");
throw new RuntimeException("SettingsFragment was created without arguments.");
}
// TODO(crbug.com/1106393): This can be removed once M88 is no longer supported.
if (WebLayer.getSupportedMajorVersionInternal() < 89) {
return WebLayer.loadSync(appContext)
.connectSiteSettingsFragment(getRemoteFragmentClient(), args)
.asRemoteFragment();
}
return WebLayer.loadSync(appContext)
.connectSettingsFragment(getRemoteFragmentClient(), args)
.asRemoteFragment();
} catch (Exception e) {
throw new RuntimeException("Failed to initialize WebLayer", e);
}
......
......@@ -6,127 +6,37 @@ package org.chromium.weblayer;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.appcompat.app.AppCompatActivity;
import org.chromium.weblayer_private.interfaces.SiteSettingsIntentHelper;
/**
* An Activity that displays various Site Settings UIs.
*
* @deprecated Use SettingsActivity instead
*/
public class SiteSettingsActivity extends AppCompatActivity {
private static final String FRAGMENT_TAG = "siteSettingsFragment";
/** The current instance of SiteSettingsActivity in the resumed state, if any. */
private static SiteSettingsActivity sResumedInstance;
/** Whether this activity has been created for the first time but not yet resumed. */
private boolean mIsNewlyCreated;
@Deprecated
public class SiteSettingsActivity extends SettingsActivity {
private static boolean sActivityNotExportedChecked;
/**
* Creates an Intent that will launch the root/full Site Settings UI, which displays a list of
* settings categories.
*/
/** @deprecated Use SettingsActivity#createIntentForSiteSettingsCategoryList instead */
@Deprecated
public static Intent createIntentForCategoryList(Context context, String profileName) {
return SiteSettingsIntentHelper.createIntentForCategoryList(
context, profileName, "".equals(profileName));
return SettingsActivity.createIntentForSiteSettingsCategoryList(context, profileName);
}
/**
* Creates an Intent that will launch the root/full Site Settings UI, which displays a list of
* settings categories.
*
* @param profileName The name of the profile.
* @param isIncognito If the profile is incognito.
*
* @deprecated Use SettingsActivity#createIntentForSiteSettingsCategoryList instead
* @since 87
*/
@Deprecated
public static Intent createIntentForCategoryList(
Context context, String profileName, boolean isIncognito) {
return SiteSettingsIntentHelper.createIntentForCategoryList(
return SettingsActivity.createIntentForSiteSettingsCategoryList(
context, profileName, isIncognito);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
ensureActivityNotExported();
super.onCreate(savedInstanceState);
mIsNewlyCreated = savedInstanceState == null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setElevation(0);
if (getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG) == null) {
SiteSettingsFragment siteSettingsFragment = new SiteSettingsFragment();
siteSettingsFragment.setArguments(getIntent().getExtras());
getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, siteSettingsFragment, FRAGMENT_TAG)
.commitNow();
}
}
@Override
protected void onResume() {
super.onResume();
// Prevent the user from interacting with multiple instances of SiteSettingsActivity at the
// same time (e.g. in multi-instance mode on a Samsung device), which would cause many fun
// bugs.
if (sResumedInstance != null && sResumedInstance.getTaskId() != getTaskId()) {
if (mIsNewlyCreated) {
// This activity was newly created and takes precedence over sResumedInstance.
sResumedInstance.finish();
} else {
// This activity was unpaused or recreated while another instance of
// SiteSettingsActivity was already showing. The existing instance takes precedence.
finish();
return;
}
}
sResumedInstance = this;
mIsNewlyCreated = false;
}
@Override
protected void onStop() {
super.onStop();
if (sResumedInstance == this) {
sResumedInstance = null;
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
private void ensureActivityNotExported() {
if (sActivityNotExportedChecked) return;
protected boolean markActivityExportChecked() {
boolean oldValue = sActivityNotExportedChecked;
sActivityNotExportedChecked = true;
try {
ActivityInfo activityInfo = getPackageManager().getActivityInfo(getComponentName(), 0);
// If SiteSettingsActivity is exported, then it's vulnerable to a fragment injection
// exploit:
// http://securityintelligence.com/new-vulnerability-android-framework-fragment-injection
if (activityInfo.exported) {
throw new IllegalStateException("SiteSettingsActivity must not be exported.");
}
} catch (NameNotFoundException ex) {
// Something terribly wrong has happened.
throw new RuntimeException(ex);
}
return oldValue;
}
}
......@@ -30,6 +30,7 @@ import org.chromium.weblayer_private.interfaces.IBrowserFragment;
import org.chromium.weblayer_private.interfaces.IMediaRouteDialogFragment;
import org.chromium.weblayer_private.interfaces.IProfile;
import org.chromium.weblayer_private.interfaces.IRemoteFragmentClient;
import org.chromium.weblayer_private.interfaces.ISettingsFragment;
import org.chromium.weblayer_private.interfaces.ISiteSettingsFragment;
import org.chromium.weblayer_private.interfaces.IWebLayer;
import org.chromium.weblayer_private.interfaces.IWebLayerClient;
......@@ -607,6 +608,20 @@ public class WebLayer {
}
}
/**
* Returns the remote counterpart of the SettingsFragment.
*/
/* package */ ISettingsFragment connectSettingsFragment(
IRemoteFragmentClient remoteFragmentClient, Bundle fragmentArgs) {
try {
assert getSupportedMajorVersionInternal() >= 89;
return mImpl.createSettingsFragmentImpl(
remoteFragmentClient, ObjectWrapper.wrap(fragmentArgs));
} catch (RemoteException e) {
throw new APICallException(e);
}
}
/**
* Returns the remote counterpart of the SiteSettingsFragment.
*/
......
......@@ -4,7 +4,7 @@
found in the LICENSE file. -->
<resources>
<style name="Theme.WebLayer.SiteSettings" parent="Base.Theme.WebLayer.SiteSettings">
<style name="Theme.WebLayer.Settings" parent="Base.Theme.WebLayer.Settings">
<item name="android:navigationBarColor">@color/weblayer_bottom_system_nav_color</item>
<item name="android:navigationBarDividerColor">@color/weblayer_bottom_system_nav_divider_color</item>
<item name="android:windowLightNavigationBar">@bool/weblayer_window_light_navigation_bar</item>
......
......@@ -4,7 +4,7 @@
found in the LICENSE file. -->
<resources>
<style name="Theme.WebLayer.SiteSettings" parent="Base.Theme.WebLayer.SiteSettings">
<style name="Theme.WebLayer.Settings" parent="Base.Theme.WebLayer.Settings">
<item name="android:navigationBarColor">@color/weblayer_bottom_system_nav_color</item>
<item name="android:navigationBarDividerColor">@color/weblayer_bottom_system_nav_divider_color</item>
<item name="android:windowLightNavigationBar">@bool/weblayer_window_light_navigation_bar</item>
......
......@@ -4,7 +4,7 @@
found in the LICENSE file. -->
<resources xmlns:tools="http://schemas.android.com/tools">
<style name="Base.Theme.WebLayer.SiteSettings" parent="Theme.AppCompat.DayNight">
<style name="Base.Theme.WebLayer.Settings" parent="Theme.AppCompat.DayNight">
<!-- Window Properties -->
<item name="android:windowBackground">@color/weblayer_default_bg_color</item>
......@@ -17,5 +17,5 @@
<item name="android:windowLightStatusBar" tools:targetApi="23">false</item>
</style>
<style name="Theme.WebLayer.SiteSettings" parent="Base.Theme.WebLayer.SiteSettings" />
<style name="Theme.WebLayer.Settings" parent="Base.Theme.WebLayer.Settings" />
</resources>
......@@ -8,7 +8,7 @@ import("//build/config/android/rules.gni")
android_library("test_java") {
testonly = true
sources = [
"org/chromium/weblayer/SiteSettingsTestUtils.java",
"org/chromium/weblayer/SettingsTestUtils.java",
"org/chromium/weblayer/TestWebLayer.java",
]
......
......@@ -7,17 +7,17 @@ package org.chromium.weblayer;
import android.content.Context;
import android.content.Intent;
import org.chromium.weblayer_private.interfaces.SiteSettingsIntentHelper;
import org.chromium.weblayer_private.interfaces.SettingsIntentHelper;
/**
* Helpers for writing tests for the Site Settings UI.
* Helpers for writing tests for the Settings UI.
*/
public final class SiteSettingsTestUtils {
// This can be removed if/when we move this into SiteSettingsActivity. Currently no embedders
public final class SettingsTestUtils {
// This can be removed if/when we move this into SettingsActivity. Currently no embedders
// need to launch the single site settings UI directly.
public static Intent createIntentForSingleWebsite(
public static Intent createIntentForSiteSettingsSingleWebsite(
Context context, String profileName, boolean isIncognito, String url) {
return SiteSettingsIntentHelper.createIntentForSingleWebsite(
return SettingsIntentHelper.createIntentForSiteSettingsSingleWebsite(
context, profileName, isIncognito, url);
}
}
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