diff --git a/res/values/strings.xml b/res/values/strings.xml index d16e4380844..b1435c95694 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6319,13 +6319,6 @@ Expand settings for application - - This setting affects all users on this tablet. - - This setting affects all users on this phone. - - Change language - Tap & pay diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 1a321274b42..a989c349bf9 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -23,9 +23,7 @@ import static android.text.format.DateUtils.FORMAT_SHOW_DATE; import android.annotation.Nullable; import android.app.ActivityManager; -import android.app.AlertDialog; import android.app.AppGlobals; -import android.app.Dialog; import android.app.Fragment; import android.app.IActivityManager; import android.app.KeyguardManager; @@ -34,7 +32,6 @@ import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; @@ -52,9 +49,6 @@ import android.graphics.Canvas; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.hardware.fingerprint.FingerprintManager; -import android.icu.text.RelativeDateTimeFormatter; -import android.icu.text.RelativeDateTimeFormatter.RelativeUnit; -import android.icu.util.ULocale; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.Network; @@ -107,7 +101,6 @@ import com.android.settings.wrapper.DevicePolicyManagerWrapper; import com.android.settings.wrapper.FingerprintManagerWrapper; import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; -import com.android.settingslib.utils.StringUtil; import java.net.InetAddress; import java.util.ArrayList; import java.util.Iterator; @@ -237,16 +230,6 @@ public final class Utils extends com.android.settingslib.Utils { return null; } - /** - * Returns the default link's IP addresses, if any, taking into account IPv4 and IPv6 style - * addresses. - * @return the formatted and newline-separated IP addresses, or null if none. - */ - public static String getDefaultIpAddresses(ConnectivityManager cm) { - LinkProperties prop = cm.getActiveLinkProperties(); - return formatIpAddresses(prop); - } - private static String formatIpAddresses(LinkProperties prop) { if (prop == null) return null; Iterator iter = prop.getAllAddresses().iterator(); @@ -400,23 +383,6 @@ public final class Utils extends com.android.settingslib.Utils { } } - /** Not global warming, it's global change warning. */ - public static Dialog buildGlobalChangeWarningDialog(final Context context, int titleResId, - final Runnable positiveAction) { - final AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(titleResId); - builder.setMessage(R.string.global_change_warning); - builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - positiveAction.run(); - } - }); - builder.setNegativeButton(android.R.string.cancel, null); - - return builder.create(); - } - public static boolean hasMultipleUsers(Context context) { return ((UserManager) context.getSystemService(Context.USER_SERVICE)) .getUsers().size() > 1; @@ -477,20 +443,11 @@ public final class Utils extends com.android.settingslib.Utils { * @param resultTo Option fragment that should receive the result of the activity launch. * @param resultRequestCode If resultTo is non-null, this is the request code in which * to report the result. - * @param titleResPackageName Optional package name for the resource id of the title. * @param titleResId resource id for the String to display for the title of this set * of preferences. * @param title String to display for the title of this set of preferences. * @param metricsCategory The current metricsCategory for logging source when fragment starts */ - public static void startWithFragment(Context context, String fragmentName, Bundle args, - Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId, - CharSequence title, int metricsCategory) { - startWithFragment(context, fragmentName, args, resultTo, resultRequestCode, - titleResPackageName, titleResId, title, false /* not a shortcut */, - metricsCategory); - } - public static void startWithFragment(Context context, String fragmentName, Bundle args, Fragment resultTo, int resultRequestCode, int titleResId, CharSequence title, boolean isShortcut, int metricsCategory) { @@ -511,7 +468,6 @@ public final class Utils extends com.android.settingslib.Utils { Intent.FLAG_ACTIVITY_NEW_TASK); } - public static void startWithFragment(Context context, String fragmentName, Bundle args, Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId, CharSequence title, boolean isShortcut, int metricsCategory, int flags) { diff --git a/src/com/android/settings/accounts/AccountTypePreference.java b/src/com/android/settings/accounts/AccountTypePreference.java index 574cbd57056..e08f11356a7 100644 --- a/src/com/android/settings/accounts/AccountTypePreference.java +++ b/src/com/android/settings/accounts/AccountTypePreference.java @@ -28,11 +28,13 @@ import android.support.v7.preference.Preference; import android.support.v7.preference.Preference.OnPreferenceClickListener; import com.android.settings.Utils; +import com.android.settings.core.SubSettingLauncher; import com.android.settings.widget.AppPreference; public class AccountTypePreference extends AppPreference implements OnPreferenceClickListener { /** * Title of the tile that is shown to the user. + * * @attr ref android.R.styleable#PreferenceHeader_title */ private final CharSequence mTitle; @@ -56,6 +58,7 @@ public class AccountTypePreference extends AppPreference implements OnPreference /** * Full class name of the fragment to display when this tile is * selected. + * * @attr ref android.R.styleable#PreferenceHeader_fragment */ private final String mFragment; @@ -92,19 +95,21 @@ public class AccountTypePreference extends AppPreference implements OnPreference public boolean onPreferenceClick(Preference preference) { if (mFragment != null) { UserManager userManager = - (UserManager) getContext().getSystemService(Context.USER_SERVICE); + (UserManager) getContext().getSystemService(Context.USER_SERVICE); UserHandle user = mFragmentArguments.getParcelable(EXTRA_USER); if (user != null && Utils.startQuietModeDialogIfNecessary(getContext(), userManager, - user.getIdentifier())) { + user.getIdentifier())) { return true; } else if (user != null && Utils.unlockWorkProfileIfNecessary(getContext(), - user.getIdentifier())) { + user.getIdentifier())) { return true; } - Utils.startWithFragment(getContext(), mFragment, mFragmentArguments, - null /* resultTo */, 0 /* resultRequestCode */, mTitleResPackageName, - mTitleResId, null /* title */,false /* isShortCut */, mMetricsCategory, - 0 /* flag */); + new SubSettingLauncher(getContext()) + .setDestination(mFragment) + .setArguments(mFragmentArguments) + .setTitle(mTitleResPackageName, mTitleResId) + .setSourceMetricsCategory(mMetricsCategory) + .launch(); return true; } return false; diff --git a/src/com/android/settings/core/SubSettingLauncher.java b/src/com/android/settings/core/SubSettingLauncher.java new file mode 100644 index 00000000000..a7879720e1b --- /dev/null +++ b/src/com/android/settings/core/SubSettingLauncher.java @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.core; + +import android.annotation.StringRes; +import android.app.Fragment; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.UserHandle; +import android.support.annotation.VisibleForTesting; + +import com.android.settings.SettingsActivity; +import com.android.settings.SubSettings; +import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; + +public class SubSettingLauncher { + + private final Context mContext; + private final LaunchRequest mLaunchRequest; + private boolean mLaunched; + + public SubSettingLauncher(Context context) { + if (context == null) { + throw new IllegalArgumentException("Context must be non-null."); + } + mContext = context; + mLaunchRequest = new LaunchRequest(); + } + + public SubSettingLauncher setDestination(String fragmentName) { + mLaunchRequest.destinationName = fragmentName; + return this; + } + + public SubSettingLauncher setTitle(@StringRes int titleResId) { + return setTitle(null /*titlePackageName*/, titleResId); + } + + public SubSettingLauncher setTitle(String titlePackageName, @StringRes int titleResId) { + mLaunchRequest.titleResPackageName = titlePackageName; + mLaunchRequest.titleResId = titleResId; + mLaunchRequest.title = null; + return this; + } + + public SubSettingLauncher setTitle(CharSequence title) { + mLaunchRequest.title = title; + return this; + } + + public SubSettingLauncher setIsShortCut(boolean isShortCut) { + mLaunchRequest.isShortCut = isShortCut; + return this; + } + + public SubSettingLauncher setArguments(Bundle arguments) { + mLaunchRequest.arguments = arguments; + return this; + } + + public SubSettingLauncher setSourceMetricsCategory(int sourceMetricsCategory) { + mLaunchRequest.sourceMetricsCategory = sourceMetricsCategory; + return this; + } + + public SubSettingLauncher setResultListener(Fragment listener, int resultRequestCode) { + mLaunchRequest.mRequestCode = resultRequestCode; + mLaunchRequest.mResultListener = listener; + return this; + } + + public SubSettingLauncher addFlags(int flags) { + mLaunchRequest.flags |= flags; + return this; + } + + public SubSettingLauncher setUserHandle(UserHandle userHandle) { + mLaunchRequest.userHandle = userHandle; + return this; + } + + public void launch() { + if (mLaunched) { + throw new IllegalStateException( + "This launcher has already been executed. Do not reuse"); + } + mLaunched = true; + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClass(mContext, SubSettings.class); + + intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, mLaunchRequest.destinationName); + intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, mLaunchRequest.arguments); + intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME, + mLaunchRequest.titleResPackageName); + intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, + mLaunchRequest.titleResId); + intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, mLaunchRequest.title); + intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, + mLaunchRequest.isShortCut); + intent.putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY, + mLaunchRequest.sourceMetricsCategory); + intent.addFlags(mLaunchRequest.flags); + + if (mLaunchRequest.userHandle != null + && mLaunchRequest.userHandle.getIdentifier() != UserHandle.myUserId()) { + launchAsUser(mContext, intent, mLaunchRequest.userHandle); + } else if (mLaunchRequest.mResultListener != null) { + launchForResult(mLaunchRequest.mResultListener, intent, mLaunchRequest.mRequestCode); + } else { + launch(intent); + } + } + + @VisibleForTesting + void launch(Intent intent) { + mContext.startActivity(intent); + } + + private static void launchForResult(Fragment listener, Intent intent, int requestCode) { + listener.getActivity().startActivityForResult(intent, requestCode); + } + + private static void launchAsUser(Context context, Intent intent, UserHandle userHandle) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + context.startActivityAsUser(intent, userHandle); + } + + /** + * Simple container that has information about how to launch a subsetting. + */ + static class LaunchRequest { + String destinationName; + int titleResId; + String titleResPackageName; + CharSequence title; + boolean isShortCut; + int sourceMetricsCategory; + int flags; + Fragment mResultListener; + int mRequestCode; + UserHandle userHandle; + Bundle arguments; + } +} diff --git a/tests/robotests/src/com/android/settings/core/SubSettingLauncherTest.java b/tests/robotests/src/com/android/settings/core/SubSettingLauncherTest.java new file mode 100644 index 00000000000..abb3312f6f3 --- /dev/null +++ b/tests/robotests/src/com/android/settings/core/SubSettingLauncherTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.core; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.Intent; + +import com.android.settings.SettingsActivity; +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SubSettingLauncherTest { + + private Context mContext; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + } + + @Test(expected = IllegalStateException.class) + public void cannotReuseLauncher() { + final SubSettingLauncher launcher = spy(new SubSettingLauncher(mContext)); + doNothing().when(launcher).launch(any(Intent.class)); + launcher.launch(); + launcher.launch(); + } + + @Test + public void launch_shouldIncludeAllParams() { + final ArgumentCaptor intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); + final SubSettingLauncher launcher = spy(new SubSettingLauncher(mContext)); + launcher.setTitle("123") + .setDestination(SubSettingLauncherTest.class.getName()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + .launch(); + doNothing().when(launcher).launch(any(Intent.class)); + verify(launcher).launch(intentArgumentCaptor.capture()); + final Intent intent = intentArgumentCaptor.getValue(); + + assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE)) + .isEqualTo("123"); + assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)) + .isEqualTo(SubSettingLauncherTest.class.getName()); + assertThat(intent.getFlags()).isEqualTo(Intent.FLAG_ACTIVITY_NEW_TASK); + } +}