Refactor Utils.startWithFragment to SubSettingLauncher

- Use the new launcher in AccountTypePrefernce for now. Will migrate the
  rest in follow up CLs.

Change-Id: I67aa49f54b39ecea4ecfdc32ccbd827d21fc79b8
Bug: 73250851
Test: robotest
This commit is contained in:
Fan Zhang
2018-02-15 13:56:56 -08:00
parent 49c8080a50
commit 2ecef333e9
5 changed files with 248 additions and 58 deletions

View File

@@ -6319,13 +6319,6 @@
<!-- Applicaitons with restrictions - settings button [CHAR LIMIT=30] --> <!-- Applicaitons with restrictions - settings button [CHAR LIMIT=30] -->
<string name="apps_with_restrictions_settings_button">Expand settings for application</string> <string name="apps_with_restrictions_settings_button">Expand settings for application</string>
<!-- Warning message when changing a global setting for a tablet.[CHAR LIMIT=none] -->
<string name="global_change_warning" product="tablet">This setting affects all users on this tablet.</string>
<!-- Warning message when changing a global setting for a phone.[CHAR LIMIT=none] -->
<string name="global_change_warning" product="default">This setting affects all users on this phone.</string>
<!-- Warning message title for global locale change [CHAR LIMIT=40] -->
<string name="global_locale_change_title">Change language</string>
<!-- NFC payment settings --><skip/> <!-- NFC payment settings --><skip/>
<string name="nfc_payment_settings_title">Tap &amp; pay</string> <string name="nfc_payment_settings_title">Tap &amp; pay</string>
<!-- Caption for button linking to a page explaining how Tap and Pay works--> <!-- Caption for button linking to a page explaining how Tap and Pay works-->

View File

@@ -23,9 +23,7 @@ import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.AppGlobals; import android.app.AppGlobals;
import android.app.Dialog;
import android.app.Fragment; import android.app.Fragment;
import android.app.IActivityManager; import android.app.IActivityManager;
import android.app.KeyguardManager; import android.app.KeyguardManager;
@@ -34,7 +32,6 @@ import android.content.ActivityNotFoundException;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
@@ -52,9 +49,6 @@ import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.hardware.fingerprint.FingerprintManager; 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.ConnectivityManager;
import android.net.LinkProperties; import android.net.LinkProperties;
import android.net.Network; import android.net.Network;
@@ -107,7 +101,6 @@ import com.android.settings.wrapper.DevicePolicyManagerWrapper;
import com.android.settings.wrapper.FingerprintManagerWrapper; import com.android.settings.wrapper.FingerprintManagerWrapper;
import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin;
import com.android.settingslib.utils.StringUtil;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator; import java.util.Iterator;
@@ -237,16 +230,6 @@ public final class Utils extends com.android.settingslib.Utils {
return null; 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) { private static String formatIpAddresses(LinkProperties prop) {
if (prop == null) return null; if (prop == null) return null;
Iterator<InetAddress> iter = prop.getAllAddresses().iterator(); Iterator<InetAddress> 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) { public static boolean hasMultipleUsers(Context context) {
return ((UserManager) context.getSystemService(Context.USER_SERVICE)) return ((UserManager) context.getSystemService(Context.USER_SERVICE))
.getUsers().size() > 1; .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 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 * @param resultRequestCode If resultTo is non-null, this is the request code in which
* to report the result. * 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 * @param titleResId resource id for the String to display for the title of this set
* of preferences. * of preferences.
* @param title 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 * @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, public static void startWithFragment(Context context, String fragmentName, Bundle args,
Fragment resultTo, int resultRequestCode, int titleResId, Fragment resultTo, int resultRequestCode, int titleResId,
CharSequence title, boolean isShortcut, int metricsCategory) { CharSequence title, boolean isShortcut, int metricsCategory) {
@@ -511,7 +468,6 @@ public final class Utils extends com.android.settingslib.Utils {
Intent.FLAG_ACTIVITY_NEW_TASK); Intent.FLAG_ACTIVITY_NEW_TASK);
} }
public static void startWithFragment(Context context, String fragmentName, Bundle args, public static void startWithFragment(Context context, String fragmentName, Bundle args,
Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId, Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId,
CharSequence title, boolean isShortcut, int metricsCategory, int flags) { CharSequence title, boolean isShortcut, int metricsCategory, int flags) {

View File

@@ -28,11 +28,13 @@ import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener; import android.support.v7.preference.Preference.OnPreferenceClickListener;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.widget.AppPreference; import com.android.settings.widget.AppPreference;
public class AccountTypePreference extends AppPreference implements OnPreferenceClickListener { public class AccountTypePreference extends AppPreference implements OnPreferenceClickListener {
/** /**
* Title of the tile that is shown to the user. * Title of the tile that is shown to the user.
*
* @attr ref android.R.styleable#PreferenceHeader_title * @attr ref android.R.styleable#PreferenceHeader_title
*/ */
private final CharSequence mTitle; 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 * Full class name of the fragment to display when this tile is
* selected. * selected.
*
* @attr ref android.R.styleable#PreferenceHeader_fragment * @attr ref android.R.styleable#PreferenceHeader_fragment
*/ */
private final String mFragment; private final String mFragment;
@@ -92,19 +95,21 @@ public class AccountTypePreference extends AppPreference implements OnPreference
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
if (mFragment != null) { if (mFragment != null) {
UserManager userManager = UserManager userManager =
(UserManager) getContext().getSystemService(Context.USER_SERVICE); (UserManager) getContext().getSystemService(Context.USER_SERVICE);
UserHandle user = mFragmentArguments.getParcelable(EXTRA_USER); UserHandle user = mFragmentArguments.getParcelable(EXTRA_USER);
if (user != null && Utils.startQuietModeDialogIfNecessary(getContext(), userManager, if (user != null && Utils.startQuietModeDialogIfNecessary(getContext(), userManager,
user.getIdentifier())) { user.getIdentifier())) {
return true; return true;
} else if (user != null && Utils.unlockWorkProfileIfNecessary(getContext(), } else if (user != null && Utils.unlockWorkProfileIfNecessary(getContext(),
user.getIdentifier())) { user.getIdentifier())) {
return true; return true;
} }
Utils.startWithFragment(getContext(), mFragment, mFragmentArguments, new SubSettingLauncher(getContext())
null /* resultTo */, 0 /* resultRequestCode */, mTitleResPackageName, .setDestination(mFragment)
mTitleResId, null /* title */,false /* isShortCut */, mMetricsCategory, .setArguments(mFragmentArguments)
0 /* flag */); .setTitle(mTitleResPackageName, mTitleResId)
.setSourceMetricsCategory(mMetricsCategory)
.launch();
return true; return true;
} }
return false; return false;

View File

@@ -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;
}
}

View File

@@ -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<Intent> 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);
}
}