diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 1951afd82ea..d258c46da45 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3016,7 +3016,7 @@ android:theme="@style/Transparent" android:excludeFromRecents="true" android:launchMode="singleTop"> - + diff --git a/res/layout/preference_volume_slider.xml b/res/layout/preference_volume_slider.xml index 107a8ae9b53..4bed21850b7 100644 --- a/res/layout/preference_volume_slider.xml +++ b/res/layout/preference_volume_slider.xml @@ -87,6 +87,7 @@ android:id="@+id/suppression_text" android:layout_width="match_parent" android:layout_height="wrap_content" + android:paddingStart="16dp" android:layout_gravity="center_vertical|start" android:textAlignment="viewStart" android:singleLine="true" diff --git a/res/layout/wifi_dialog.xml b/res/layout/wifi_dialog.xml index 2c4a1edfdff..f18f21be837 100644 --- a/res/layout/wifi_dialog.xml +++ b/res/layout/wifi_dialog.xml @@ -54,7 +54,9 @@ style="@style/wifi_item_edit_content" android:hint="@string/wifi_ssid_hint" android:singleLine="true" - android:inputType="textNoSuggestions" /> + android:inputType="textNoSuggestions"> + + Expand settings for application - - This setting affects all users on this tablet. - - This setting affects all users on this phone. - - Change language - Tap & pay @@ -9225,6 +9218,8 @@ Do you want to remove this instant app? + + Open Games diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 76b48d1f271..84b107191af 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -59,6 +59,7 @@ import com.android.settings.Settings.WifiSettingsActivity; import com.android.settings.applications.manageapplications.ManageApplications; import com.android.settings.backup.BackupSettingsActivity; import com.android.settings.core.FeatureFlags; +import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.gateway.SettingsGateway; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.DashboardSummary; @@ -612,11 +613,10 @@ public class SettingsActivity extends SettingsDrawerActivity * @param fragmentClass Full name of the class implementing the fragment. * @param args Any desired arguments to supply to the fragment. * @param titleRes Optional resource identifier of the title of this fragment. - * @param titleText Optional text of the title of this fragment. * @param userHandle The user for which the panel has to be started. */ public void startPreferencePanelAsUser(Fragment caller, String fragmentClass, - Bundle args, int titleRes, CharSequence titleText, UserHandle userHandle) { + Bundle args, int titleRes, UserHandle userHandle) { // This is a workaround. // // Calling startWithFragmentAsUser() without specifying FLAG_ACTIVITY_NEW_TASK to the intent @@ -628,19 +628,17 @@ public class SettingsActivity extends SettingsDrawerActivity // another check here to call startPreferencePanel() instead of startWithFragmentAsUser() // when we're calling it as the same user. if (userHandle.getIdentifier() == UserHandle.myUserId()) { - startPreferencePanel(caller, fragmentClass, args, titleRes, titleText, null, 0); + startPreferencePanel(caller, fragmentClass, args, titleRes, null /* titleText */, + null, 0); } else { - String title = null; - if (titleRes < 0) { - if (titleText != null) { - title = titleText.toString(); - } else { - // There not much we can do in that case - title = ""; - } - } - Utils.startWithFragmentAsUser(this, fragmentClass, args, titleRes, title, - mIsShortcut, mMetricsFeatureProvider.getMetricsCategory(caller), userHandle); + new SubSettingLauncher(this) + .setDestination(fragmentClass) + .setArguments(args) + .setTitle(titleRes) + .setIsShortCut(mIsShortcut) + .setSourceMetricsCategory(mMetricsFeatureProvider.getMetricsCategory(caller)) + .setUserHandle(userHandle) + .launch(); } } diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 1a321274b42..3923da5ed6a 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; @@ -446,26 +412,6 @@ public final class Utils extends com.android.settingslib.Utils { metricsCategory); } - - /** - * Start a new instance of the activity, showing only the given fragment. - * When launched in this mode, the given preference fragment will be instantiated and fill the - * entire activity. - * - * @param context The context. - * @param fragmentName The name of the fragment to display. - * @param titleResId resource id for the String to display for the title of this set - * of preferences. - * @param metricsCategory The current metricsCategory for logging source when fragment starts - * @param intentFlags flag that should be added to the intent. - */ - public static void startWithFragment(Context context, String fragmentName, int titleResId, - int metricsCategory, int intentFlags) { - startWithFragment(context, fragmentName, null, null, 0, - null /* titleResPackageName */, titleResId, null, false /* not a shortcut */, - metricsCategory, intentFlags); - } - /** * Start a new instance of the activity, showing only the given fragment. * When launched in this mode, the given preference fragment will be instantiated and fill the @@ -477,20 +423,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) { @@ -506,18 +443,9 @@ public final class Utils extends com.android.settingslib.Utils { public static void startWithFragment(Context context, String fragmentName, Bundle args, Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId, CharSequence title, boolean isShortcut, int metricsCategory) { - startWithFragment(context, fragmentName, args, resultTo, resultRequestCode, - titleResPackageName, titleResId, title, isShortcut, metricsCategory, - 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) { Intent intent = onBuildStartFragmentIntent(context, fragmentName, args, titleResPackageName, titleResId, title, isShortcut, metricsCategory); - intent.addFlags(flags); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (resultTo == null) { context.startActivity(intent); } else { @@ -525,22 +453,6 @@ public final class Utils extends com.android.settingslib.Utils { } } - public static void startWithFragmentAsUser(Context context, String fragmentName, Bundle args, - int titleResId, CharSequence title, boolean isShortcut, int metricsCategory, - UserHandle userHandle) { - // workaround to avoid crash in b/17523189 - if (userHandle.getIdentifier() == UserHandle.myUserId()) { - startWithFragment(context, fragmentName, args, null, 0, titleResId, title, isShortcut, - metricsCategory); - } else { - Intent intent = onBuildStartFragmentIntent(context, fragmentName, args, - null /* titleResPackageName */, titleResId, title, isShortcut, metricsCategory); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - context.startActivityAsUser(intent, userHandle); - } - } - /** * Build an Intent to launch a new activity showing the selected fragment. * The implementation constructs an Intent that re-launches the current activity with the diff --git a/src/com/android/settings/accounts/AccountDashboardFragment.java b/src/com/android/settings/accounts/AccountDashboardFragment.java index 0a4c343b2bc..9702102a862 100644 --- a/src/com/android/settings/accounts/AccountDashboardFragment.java +++ b/src/com/android/settings/accounts/AccountDashboardFragment.java @@ -22,6 +22,7 @@ import android.content.Context; import android.os.UserHandle; import android.provider.SearchIndexableResource; import android.text.BidiFormatter; +import android.text.TextUtils; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; @@ -94,17 +95,21 @@ public class AccountDashboardFragment extends DashboardFragment { if (types == null || types.length == 0) { summary = mContext.getString(R.string.account_dashboard_default_summary); } else { - // Show up to 3 account types - final int size = Math.min(3, types.length); + // Show up to 3 account types, ignore any null value + int accountToAdd = Math.min(3, types.length); - for (int i = 0; i < size; i++) { + for (int i = 0; i < types.length && accountToAdd > 0; i++) { final CharSequence label = authHelper.getLabelForType(mContext, types[i]); + if (TextUtils.isEmpty(label)) { + continue; + } if (summary == null) { summary = bidiFormatter.unicodeWrap(label); } else { summary = mContext.getString(R.string.join_many_items_middle, summary, bidiFormatter.unicodeWrap(label)); } + accountToAdd--; } } mSummaryLoader.setSummary(this, summary); 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/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index 5e12503ddaf..a5f06a557f2 100755 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -505,10 +505,12 @@ public class AppInfoDashboardFragment extends DashboardFragment mDisableAfterUninstall = andDisable; } - public static void startAppInfoFragment(Class fragment, int title, + public static void startAppInfoFragment(Class fragment, int title, Bundle args, SettingsPreferenceFragment caller, AppEntry appEntry) { // start new fragment to display extended information - final Bundle args = new Bundle(); + if (args == null) { + args = new Bundle(); + } args.putString(ARG_PACKAGE_NAME, appEntry.info.packageName); args.putInt(ARG_PACKAGE_UID, appEntry.info.uid); diff --git a/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBase.java b/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBase.java index 105a01e38f4..fd545a7bef5 100644 --- a/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBase.java +++ b/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBase.java @@ -17,6 +17,7 @@ package com.android.settings.applications.appinfo; import android.content.Context; +import android.os.Bundle; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import android.text.TextUtils; @@ -58,7 +59,7 @@ public abstract class AppInfoPreferenceControllerBase extends BasePreferenceCont public boolean handlePreferenceTreeClick(Preference preference) { if (TextUtils.equals(preference.getKey(), mPreferenceKey) && mDetailFragmenClass != null) { AppInfoDashboardFragment.startAppInfoFragment( - mDetailFragmenClass, -1, mParent, mParent.getAppEntry()); + mDetailFragmenClass, -1, getArguments(), mParent, mParent.getAppEntry()); return true; } return false; @@ -77,4 +78,12 @@ public abstract class AppInfoPreferenceControllerBase extends BasePreferenceCont return null; } + /** + * Gets any extras that should be passed to the fragment class when the preference is clicked. + * @return a bundle of extras to include in the launch intent + */ + protected Bundle getArguments() { + return null; + } + } diff --git a/src/com/android/settings/applications/appinfo/AppNotificationPreferenceController.java b/src/com/android/settings/applications/appinfo/AppNotificationPreferenceController.java index 1f1950418b3..5a970f6f390 100644 --- a/src/com/android/settings/applications/appinfo/AppNotificationPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppNotificationPreferenceController.java @@ -16,7 +16,10 @@ package com.android.settings.applications.appinfo; +import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY; + import android.content.Context; +import android.os.Bundle; import android.support.v7.preference.Preference; import com.android.settings.SettingsPreferenceFragment; @@ -27,12 +30,17 @@ import com.android.settingslib.applications.ApplicationsState; public class AppNotificationPreferenceController extends AppInfoPreferenceControllerBase { private static final String KEY_NOTIFICATION = "notification_settings"; + private String mChannelId = null; // Used for updating notification preference. private final NotificationBackend mBackend = new NotificationBackend(); public AppNotificationPreferenceController(Context context, AppInfoDashboardFragment parent) { super(context, parent, KEY_NOTIFICATION); + if (parent != null && parent.getActivity() != null + && parent.getActivity().getIntent() != null) { + mChannelId = parent.getActivity().getIntent().getStringExtra(EXTRA_FRAGMENT_ARG_KEY); + } } @Override @@ -45,6 +53,16 @@ public class AppNotificationPreferenceController extends AppInfoPreferenceContro return AppNotificationSettings.class; } + @Override + protected Bundle getArguments() { + Bundle bundle = null; + if (mChannelId != null) { + bundle = new Bundle(); + bundle.putString(EXTRA_FRAGMENT_ARG_KEY, mChannelId); + } + return bundle; + } + private CharSequence getNotificationSummary(ApplicationsState.AppEntry appEntry, Context context, NotificationBackend backend) { NotificationBackend.AppRow appRow = diff --git a/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java b/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java index 331907b2259..35b7c27605c 100644 --- a/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java +++ b/src/com/android/settings/bluetooth/BluetoothMasterSwitchPreferenceController.java @@ -88,7 +88,7 @@ public class BluetoothMasterSwitchPreferenceController extends AbstractPreferenc public boolean handlePreferenceTreeClick(Preference preference) { if (KEY_TOGGLE_BLUETOOTH.equals(preference.getKey())) { mActivity.startPreferencePanelAsUser(mFragment, BluetoothSettings.class.getName(), null, - R.string.bluetooth, null, new UserHandle(UserHandle.myUserId())); + R.string.bluetooth, new UserHandle(UserHandle.myUserId())); return true; } return super.handlePreferenceTreeClick(preference); diff --git a/src/com/android/settings/bluetooth/BluetoothPairingPreferenceController.java b/src/com/android/settings/bluetooth/BluetoothPairingPreferenceController.java index 8ac64e8938c..89826fe17d6 100644 --- a/src/com/android/settings/bluetooth/BluetoothPairingPreferenceController.java +++ b/src/com/android/settings/bluetooth/BluetoothPairingPreferenceController.java @@ -60,7 +60,7 @@ public class BluetoothPairingPreferenceController extends AbstractPreferenceCont public boolean handlePreferenceTreeClick(Preference preference) { if (KEY_PAIRING.equals(preference.getKey())) { mActivity.startPreferencePanelAsUser(mFragment, BluetoothPairingDetail.class.getName(), - null, R.string.bluetooth_pairing_page_title, null, + null, R.string.bluetooth_pairing_page_title, new UserHandle(UserHandle.myUserId())); return true; } diff --git a/src/com/android/settings/core/SubSettingLauncher.java b/src/com/android/settings/core/SubSettingLauncher.java new file mode 100644 index 00000000000..8e0f85942e5 --- /dev/null +++ b/src/com/android/settings/core/SubSettingLauncher.java @@ -0,0 +1,168 @@ +/* + * 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 android.text.TextUtils; + +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); + if (TextUtils.isEmpty(mLaunchRequest.destinationName)) { + throw new IllegalArgumentException("Destination fragment must be set"); + } + intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, mLaunchRequest.destinationName); + + if (mLaunchRequest.sourceMetricsCategory <= 0) { + throw new IllegalArgumentException("Source metrics category must be set"); + } + intent.putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY, + mLaunchRequest.sourceMetricsCategory); + + 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.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 = -100; + int flags; + Fragment mResultListener; + int mRequestCode; + UserHandle userHandle; + Bundle arguments; + } +} diff --git a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java index 275af3df7eb..29d66bd5b44 100644 --- a/src/com/android/settings/dashboard/DashboardFragmentRegistry.java +++ b/src/com/android/settings/dashboard/DashboardFragmentRegistry.java @@ -19,12 +19,11 @@ package com.android.settings.dashboard; import android.util.ArrayMap; import com.android.settings.DisplaySettings; -import com.android.settings.accounts.AccountDetailDashboardFragment; import com.android.settings.accounts.AccountDashboardFragment; +import com.android.settings.accounts.AccountDetailDashboardFragment; import com.android.settings.applications.AppAndNotificationDashboardFragment; import com.android.settings.applications.DefaultAppSettings; import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment; -import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragmentOld; import com.android.settings.development.DevelopmentSettingsDashboardFragment; import com.android.settings.deviceinfo.StorageDashboardFragment; import com.android.settings.fuelgauge.PowerUsageSummary; @@ -60,9 +59,6 @@ public class DashboardFragmentRegistry { PARENT_TO_CATEGORY_KEY_MAP = new ArrayMap<>(); PARENT_TO_CATEGORY_KEY_MAP.put( NetworkDashboardFragment.class.getName(), CategoryKey.CATEGORY_NETWORK); - //TODO(b/69471219): update ConnectedDeviceDashboardFragment once new feature is done. - PARENT_TO_CATEGORY_KEY_MAP.put(ConnectedDeviceDashboardFragmentOld.class.getName(), - CategoryKey.CATEGORY_DEVICE); PARENT_TO_CATEGORY_KEY_MAP.put(AdvancedConnectedDeviceDashboardFragment.class.getName(), CategoryKey.CATEGORY_DEVICE); PARENT_TO_CATEGORY_KEY_MAP.put(AppAndNotificationDashboardFragment.class.getName(), diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccess.java b/src/com/android/settings/datausage/UnrestrictedDataAccess.java index 2e204063bdb..83ff755f21a 100644 --- a/src/com/android/settings/datausage/UnrestrictedDataAccess.java +++ b/src/com/android/settings/datausage/UnrestrictedDataAccess.java @@ -285,6 +285,7 @@ public class UnrestrictedDataAccess extends SettingsPreferenceFragment // app is blacklisted, launch App Data Usage screen AppInfoDashboardFragment.startAppInfoFragment(AppDataUsage.class, R.string.app_data_usage, + null /* arguments */, UnrestrictedDataAccess.this, mEntry); } else { diff --git a/src/com/android/settings/development/EmulateDisplayCutoutPreferenceController.java b/src/com/android/settings/development/EmulateDisplayCutoutPreferenceController.java index d6c74f911eb..34b3996d8c2 100644 --- a/src/com/android/settings/development/EmulateDisplayCutoutPreferenceController.java +++ b/src/com/android/settings/development/EmulateDisplayCutoutPreferenceController.java @@ -19,20 +19,18 @@ package com.android.settings.development; import static android.os.UserHandle.USER_SYSTEM; import android.content.Context; -import android.content.om.IOverlayManager; -import android.content.om.OverlayInfo; import android.content.pm.PackageManager; -import android.os.RemoteException; -import android.os.ServiceManager; import android.support.annotation.VisibleForTesting; import android.support.v7.preference.ListPreference; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import android.text.TextUtils; +import android.view.DisplayCutout; -import com.android.internal.util.ArrayUtils; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.wrapper.OverlayManagerWrapper; +import com.android.settings.wrapper.OverlayManagerWrapper.OverlayInfo; import com.android.settingslib.development.DeveloperOptionsPreferenceController; import java.util.List; @@ -41,11 +39,9 @@ public class EmulateDisplayCutoutPreferenceController extends DeveloperOptionsPreferenceController implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin { - public static final String EMULATION_OVERLAY_PREFIX = - "com.android.internal.display.cutout.emulation."; private static final String KEY = "display_cutout_emulation"; - private final IOverlayManager mOverlayManager; + private final OverlayManagerWrapper mOverlayManager; private final boolean mAvailable; private ListPreference mPreference; @@ -53,7 +49,7 @@ public class EmulateDisplayCutoutPreferenceController extends @VisibleForTesting EmulateDisplayCutoutPreferenceController(Context context, PackageManager packageManager, - IOverlayManager overlayManager) { + OverlayManagerWrapper overlayManager) { super(context); mOverlayManager = overlayManager; mPackageManager = packageManager; @@ -61,8 +57,7 @@ public class EmulateDisplayCutoutPreferenceController extends } public EmulateDisplayCutoutPreferenceController(Context context) { - this(context, context.getPackageManager(), IOverlayManager.Stub.asInterface( - ServiceManager.getService(Context.OVERLAY_SERVICE))); + this(context, context.getPackageManager(), new OverlayManagerWrapper()); } @Override @@ -93,7 +88,7 @@ public class EmulateDisplayCutoutPreferenceController extends private boolean setEmulationOverlay(String packageName) { OverlayInfo[] overlays = getOverlayInfos(); - CharSequence currentPackageName = null; + String currentPackageName = null; for (OverlayInfo o : overlays) { if (o.isEnabled()) { currentPackageName = o.packageName; @@ -106,19 +101,14 @@ public class EmulateDisplayCutoutPreferenceController extends return true; } - for (OverlayInfo o : overlays) { - boolean isEnabled = o.isEnabled(); - boolean shouldBeEnabled = TextUtils.equals(o.packageName, packageName); - if (isEnabled != shouldBeEnabled) { - try { - mOverlayManager.setEnabled(o.packageName, shouldBeEnabled, USER_SYSTEM); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + final boolean result; + if (TextUtils.isEmpty(packageName)) { + result = mOverlayManager.setEnabled(currentPackageName, false, USER_SYSTEM); + } else { + result = mOverlayManager.setEnabledExclusiveInCategory(packageName, USER_SYSTEM); } updateState(mPreference); - return true; + return result; } @Override @@ -155,18 +145,15 @@ public class EmulateDisplayCutoutPreferenceController extends } private OverlayInfo[] getOverlayInfos() { - try { - @SuppressWarnings("unchecked") List overlayInfos = - mOverlayManager.getOverlayInfosForTarget("android", USER_SYSTEM); - for (int i = overlayInfos.size() - 1; i >= 0; i--) { - if (!overlayInfos.get(i).packageName.startsWith(EMULATION_OVERLAY_PREFIX)) { - overlayInfos.remove(i); - } + @SuppressWarnings("unchecked") List overlayInfos = + mOverlayManager.getOverlayInfosForTarget("android", USER_SYSTEM); + for (int i = overlayInfos.size() - 1; i >= 0; i--) { + if (!DisplayCutout.EMULATION_OVERLAY_CATEGORY.equals( + overlayInfos.get(i).category)) { + overlayInfos.remove(i); } - return overlayInfos.toArray(new OverlayInfo[overlayInfos.size()]); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); } + return overlayInfos.toArray(new OverlayInfo[overlayInfos.size()]); } @Override @@ -180,4 +167,5 @@ public class EmulateDisplayCutoutPreferenceController extends updateState(mPreference); mPreference.setEnabled(false); } + } diff --git a/src/com/android/settings/display/ThemePreferenceController.java b/src/com/android/settings/display/ThemePreferenceController.java index 9c1314ebc5e..ff31dbdc80f 100644 --- a/src/com/android/settings/display/ThemePreferenceController.java +++ b/src/com/android/settings/display/ThemePreferenceController.java @@ -14,8 +14,6 @@ package com.android.settings.display; import android.content.Context; -import android.content.om.IOverlayManager; -import android.content.om.OverlayInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -30,6 +28,8 @@ import android.text.TextUtils; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.overlay.FeatureFactory; +import com.android.settings.wrapper.OverlayManagerWrapper; +import com.android.settings.wrapper.OverlayManagerWrapper.OverlayInfo; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -46,16 +46,16 @@ public class ThemePreferenceController extends AbstractPreferenceController impl private static final String KEY_THEME = "theme"; private final MetricsFeatureProvider mMetricsFeatureProvider; - private final OverlayManager mOverlayService; + private final OverlayManagerWrapper mOverlayService; private final PackageManager mPackageManager; public ThemePreferenceController(Context context) { this(context, ServiceManager.getService(Context.OVERLAY_SERVICE) != null - ? new OverlayManager() : null); + ? new OverlayManagerWrapper() : null); } @VisibleForTesting - ThemePreferenceController(Context context, OverlayManager overlayManager) { + ThemePreferenceController(Context context, OverlayManagerWrapper overlayManager) { super(context); mOverlayService = overlayManager; mPackageManager = context.getPackageManager(); @@ -114,17 +114,16 @@ public class ThemePreferenceController extends AbstractPreferenceController impl if (Objects.equal(newValue, current)) { return true; } - try { - mOverlayService.setEnabledExclusive((String) newValue, true, UserHandle.myUserId()); - } catch (RemoteException e) { - return false; - } + mOverlayService.setEnabledExclusiveInCategory((String) newValue, UserHandle.myUserId()); return true; } - private boolean isChangeableOverlay(String packageName) { + private boolean isTheme(OverlayInfo oi) { + if (!OverlayInfo.CATEGORY_THEME.equals(oi.category)) { + return false; + } try { - PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0); + PackageInfo pi = mPackageManager.getPackageInfo(oi.packageName, 0); return pi != null && !pi.isStaticOverlayPackage(); } catch (PackageManager.NameNotFoundException e) { return false; @@ -132,16 +131,12 @@ public class ThemePreferenceController extends AbstractPreferenceController impl } private String getTheme() { - try { - List infos = mOverlayService.getOverlayInfosForTarget("android", - UserHandle.myUserId()); - for (int i = 0, size = infos.size(); i < size; i++) { - if (infos.get(i).isEnabled() && - isChangeableOverlay(infos.get(i).packageName)) { - return infos.get(i).packageName; - } + List infos = mOverlayService.getOverlayInfosForTarget("android", + UserHandle.myUserId()); + for (int i = 0, size = infos.size(); i < size; i++) { + if (infos.get(i).isEnabled() && isTheme(infos.get(i))) { + return infos.get(i).packageName; } - } catch (RemoteException e) { } return null; } @@ -161,37 +156,14 @@ public class ThemePreferenceController extends AbstractPreferenceController impl @VisibleForTesting String[] getAvailableThemes() { - try { - List infos = mOverlayService.getOverlayInfosForTarget("android", - UserHandle.myUserId()); - List pkgs = new ArrayList(infos.size()); - for (int i = 0, size = infos.size(); i < size; i++) { - if (isChangeableOverlay(infos.get(i).packageName)) { - pkgs.add(infos.get(i).packageName); - } + List infos = mOverlayService.getOverlayInfosForTarget("android", + UserHandle.myUserId()); + List pkgs = new ArrayList<>(infos.size()); + for (int i = 0, size = infos.size(); i < size; i++) { + if (isTheme(infos.get(i))) { + pkgs.add(infos.get(i).packageName); } - return pkgs.toArray(new String[pkgs.size()]); - } catch (RemoteException e) { - } - return new String[0]; - } - - public static class OverlayManager { - private final IOverlayManager mService; - - public OverlayManager() { - mService = IOverlayManager.Stub.asInterface( - ServiceManager.getService(Context.OVERLAY_SERVICE)); - } - - public void setEnabledExclusive(String pkg, boolean enabled, int userId) - throws RemoteException { - mService.setEnabledExclusive(pkg, enabled, userId); - } - - public List getOverlayInfosForTarget(String target, int userId) - throws RemoteException { - return mService.getOverlayInfosForTarget(target, userId); } + return pkgs.toArray(new String[pkgs.size()]); } } diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java index 981b0dc1129..6cf07a40f9e 100644 --- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java +++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java @@ -45,20 +45,20 @@ import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.applications.LayoutPreference; import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.fuelgauge.anomaly.AnomalyUtils; -import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; -import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; -import com.android.settings.wrapper.DevicePolicyManagerWrapper; import com.android.settings.fuelgauge.anomaly.Anomaly; import com.android.settings.fuelgauge.anomaly.AnomalyDialogFragment; import com.android.settings.fuelgauge.anomaly.AnomalyLoader; import com.android.settings.fuelgauge.anomaly.AnomalySummaryPreferenceController; +import com.android.settings.fuelgauge.anomaly.AnomalyUtils; +import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; +import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.widget.EntityHeaderController; +import com.android.settings.wrapper.DevicePolicyManagerWrapper; import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.core.AbstractPreferenceController; - import com.android.settingslib.utils.StringUtil; + import java.util.ArrayList; import java.util.List; @@ -158,7 +158,7 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements args.putParcelableList(EXTRA_ANOMALY_LIST, anomalies); caller.startPreferencePanelAsUser(fragment, AdvancedPowerUsageDetail.class.getName(), args, - R.string.battery_details_title, null, + R.string.battery_details_title, new UserHandle(getUserIdToLaunchAdvancePowerUsageDetail(sipper))); } @@ -189,7 +189,7 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements } caller.startPreferencePanelAsUser(fragment, AdvancedPowerUsageDetail.class.getName(), args, - R.string.battery_details_title, null, new UserHandle(UserHandle.myUserId())); + R.string.battery_details_title, new UserHandle(UserHandle.myUserId())); } @Override diff --git a/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetails.java b/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetails.java index 143733db2b8..c7972e203a8 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetails.java +++ b/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetails.java @@ -17,7 +17,6 @@ package com.android.settings.fuelgauge; import android.content.Context; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; import android.os.Bundle; @@ -69,8 +68,7 @@ public class PowerUsageAnomalyDetails extends DashboardFragment implements args.putParcelableList(EXTRA_ANOMALY_LIST, anomalies); caller.startPreferencePanelAsUser(fragment, PowerUsageAnomalyDetails.class.getName(), args, - R.string.battery_abnormal_details_title, null, - new UserHandle(UserHandle.myUserId())); + R.string.battery_abnormal_details_title, new UserHandle(UserHandle.myUserId())); } @Override diff --git a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java index e09a8a38c84..3045261311c 100644 --- a/src/com/android/settings/fuelgauge/RestrictedAppDetails.java +++ b/src/com/android/settings/fuelgauge/RestrictedAppDetails.java @@ -66,7 +66,7 @@ public class RestrictedAppDetails extends DashboardFragment { args.putParcelableList(EXTRA_PACKAGE_OPS_LIST, packageOpsList); caller.startPreferencePanelAsUser(fragment, RestrictedAppDetails.class.getName(), args, - R.string.restricted_app_title, null /* titleText */, + R.string.restricted_app_title, new UserHandle(UserHandle.myUserId())); } diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java b/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java index 2019b9d7d64..87c248820da 100644 --- a/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java +++ b/src/com/android/settings/fuelgauge/batterytip/BatteryDatabaseManager.java @@ -38,14 +38,26 @@ import java.util.List; /** * Database manager for battery data. Now it only contains anomaly data stored in {@link AppInfo}. + * + * This manager may be accessed by multi-threads. All the database related methods are synchronized + * so each operation won't be interfered by other threads. */ public class BatteryDatabaseManager { - private final AnomalyDatabaseHelper mDatabaseHelper; + private static BatteryDatabaseManager sSingleton; - public BatteryDatabaseManager(Context context) { + private AnomalyDatabaseHelper mDatabaseHelper; + + private BatteryDatabaseManager(Context context) { mDatabaseHelper = AnomalyDatabaseHelper.getInstance(context); } + public static BatteryDatabaseManager getInstance(Context context) { + if (sSingleton == null) { + sSingleton = new BatteryDatabaseManager(context); + } + return sSingleton; + } + /** * Insert an anomaly log to database. * @@ -53,7 +65,7 @@ public class BatteryDatabaseManager { * @param type the type of the anomaly * @param timestampMs the time when it is happened */ - public void insertAnomaly(String packageName, int type, long timestampMs) { + public synchronized void insertAnomaly(String packageName, int type, long timestampMs) { try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) { ContentValues values = new ContentValues(); values.put(PACKAGE_NAME, packageName); @@ -67,7 +79,7 @@ public class BatteryDatabaseManager { /** * Query all the anomalies that happened after {@code timestampMsAfter} and with {@code state}. */ - public List queryAllAnomalies(long timestampMsAfter, int state) { + public synchronized List queryAllAnomalies(long timestampMsAfter, int state) { final List appInfos = new ArrayList<>(); try (SQLiteDatabase db = mDatabaseHelper.getReadableDatabase()) { final String[] projection = {PACKAGE_NAME, ANOMALY_TYPE}; @@ -90,7 +102,7 @@ public class BatteryDatabaseManager { return appInfos; } - public void deleteAllAnomaliesBeforeTimeStamp(long timestampMs) { + public synchronized void deleteAllAnomaliesBeforeTimeStamp(long timestampMs) { try (SQLiteDatabase db = mDatabaseHelper.getWritableDatabase()) { db.delete(TABLE_ANOMALY, TIME_STAMP_MS + " < ?", new String[]{String.valueOf(timestampMs)}); @@ -103,7 +115,7 @@ public class BatteryDatabaseManager { * @param appInfos represents the anomalies * @param state which state to update to */ - public void updateAnomalies(List appInfos, int state) { + public synchronized void updateAnomalies(List appInfos, int state) { if (!appInfos.isEmpty()) { final int size = appInfos.size(); final String[] whereArgs = new String[size]; diff --git a/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java b/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java index 886a6d534e6..37f4b2a5bea 100644 --- a/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java +++ b/src/com/android/settings/fuelgauge/batterytip/actions/RestrictAppAction.java @@ -42,7 +42,7 @@ public class RestrictAppAction extends BatteryTipAction { super(context); mRestrictAppTip = tip; mBatteryUtils = BatteryUtils.getInstance(context); - mBatteryDatabaseManager = new BatteryDatabaseManager(context); + mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(context); } /** diff --git a/src/com/android/settings/fuelgauge/batterytip/actions/SmartBatteryAction.java b/src/com/android/settings/fuelgauge/batterytip/actions/SmartBatteryAction.java index cbd15812e5a..58a95ac3e19 100644 --- a/src/com/android/settings/fuelgauge/batterytip/actions/SmartBatteryAction.java +++ b/src/com/android/settings/fuelgauge/batterytip/actions/SmartBatteryAction.java @@ -18,12 +18,10 @@ package com.android.settings.fuelgauge.batterytip.actions; import android.app.Fragment; import android.os.UserHandle; -import android.support.v14.preference.PreferenceFragment; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.fuelgauge.SmartBatterySettings; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; public class SmartBatteryAction extends BatteryTipAction { private SettingsActivity mSettingsActivity; @@ -42,7 +40,7 @@ public class SmartBatteryAction extends BatteryTipAction { public void handlePositiveAction() { mSettingsActivity.startPreferencePanelAsUser(mFragment, SmartBatterySettings.class.getName(), null /* args */, - R.string.smart_battery_manager_title, null /* titleText */, + R.string.smart_battery_manager_title, new UserHandle(UserHandle.myUserId())); } } diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java index e3c9b9ed612..0bb1f17aa68 100644 --- a/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java +++ b/src/com/android/settings/fuelgauge/batterytip/detectors/RestrictAppDetector.java @@ -43,7 +43,7 @@ public class RestrictAppDetector implements BatteryTipDetector { public RestrictAppDetector(Context context, BatteryTipPolicy policy) { mPolicy = policy; - mBatteryDatabaseManager = new BatteryDatabaseManager(context); + mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(context); } @Override diff --git a/src/com/android/settings/location/RecentLocationRequestPreferenceController.java b/src/com/android/settings/location/RecentLocationRequestPreferenceController.java index b17d19ec9ce..afcdb646c0f 100644 --- a/src/com/android/settings/location/RecentLocationRequestPreferenceController.java +++ b/src/com/android/settings/location/RecentLocationRequestPreferenceController.java @@ -60,7 +60,7 @@ public class RecentLocationRequestPreferenceController extends LocationBasePrefe ((SettingsActivity) mFragment.getActivity()).startPreferencePanelAsUser( mFragment, AppInfoDashboardFragment.class.getName(), args, - R.string.application_info_label, null, mUserHandle); + R.string.application_info_label, mUserHandle); return true; } } diff --git a/src/com/android/settings/vpn2/AppManagementFragment.java b/src/com/android/settings/vpn2/AppManagementFragment.java index 9e215d1b7aa..b554c83ac8b 100644 --- a/src/com/android/settings/vpn2/AppManagementFragment.java +++ b/src/com/android/settings/vpn2/AppManagementFragment.java @@ -44,7 +44,7 @@ import com.android.internal.net.VpnConfig; import com.android.internal.util.ArrayUtils; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.Utils; +import com.android.settings.core.SubSettingLauncher; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settingslib.RestrictedPreference; import com.android.settingslib.RestrictedSwitchPreference; @@ -100,10 +100,15 @@ public class AppManagementFragment extends SettingsPreferenceFragment }; public static void show(Context context, AppPreference pref, int sourceMetricsCategory) { - Bundle args = new Bundle(); + final Bundle args = new Bundle(); args.putString(ARG_PACKAGE_NAME, pref.getPackageName()); - Utils.startWithFragmentAsUser(context, AppManagementFragment.class.getName(), args, -1, - pref.getLabel(), false, sourceMetricsCategory, new UserHandle(pref.getUserId())); + new SubSettingLauncher(context) + .setDestination(AppManagementFragment.class.getName()) + .setArguments(args) + .setTitle(pref.getLabel()) + .setSourceMetricsCategory(sourceMetricsCategory) + .setUserHandle(new UserHandle(pref.getUserId())) + .launch(); } @Override diff --git a/src/com/android/settings/wallpaper/WallpaperSuggestionActivity.java b/src/com/android/settings/wallpaper/WallpaperSuggestionActivity.java index 8d798b1ced4..0874ceaecc2 100644 --- a/src/com/android/settings/wallpaper/WallpaperSuggestionActivity.java +++ b/src/com/android/settings/wallpaper/WallpaperSuggestionActivity.java @@ -26,7 +26,7 @@ import android.support.annotation.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; -import com.android.settings.Utils; +import com.android.settings.core.SubSettingLauncher; import com.android.settings.wrapper.WallpaperManagerWrapper; public class WallpaperSuggestionActivity extends Activity { @@ -51,9 +51,12 @@ public class WallpaperSuggestionActivity extends Activity { @VisibleForTesting void startFallbackSuggestion() { // fall back to default wallpaper picker - Utils.startWithFragment(this, WallpaperTypeSettings.class.getName(), - R.string.wallpaper_suggestion_title, MetricsProto.MetricsEvent.DASHBOARD_SUMMARY, - Intent.FLAG_ACTIVITY_FORWARD_RESULT); + new SubSettingLauncher(this) + .setDestination(WallpaperTypeSettings.class.getName()) + .setTitle(R.string.wallpaper_suggestion_title) + .setSourceMetricsCategory(MetricsProto.MetricsEvent.DASHBOARD_SUMMARY) + .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT) + .launch(); } @VisibleForTesting diff --git a/src/com/android/settings/wrapper/OverlayManagerWrapper.java b/src/com/android/settings/wrapper/OverlayManagerWrapper.java new file mode 100644 index 00000000000..6e3c2348857 --- /dev/null +++ b/src/com/android/settings/wrapper/OverlayManagerWrapper.java @@ -0,0 +1,102 @@ +/* + * 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.wrapper; + +import android.content.Context; +import android.content.om.IOverlayManager; +import android.content.om.OverlayInfo; +import android.os.RemoteException; +import android.os.ServiceManager; + +import java.util.ArrayList; +import java.util.List; + +public class OverlayManagerWrapper { + + private final IOverlayManager mOverlayManager; + + public OverlayManagerWrapper(IOverlayManager overlayManager) { + mOverlayManager = overlayManager; + } + + public OverlayManagerWrapper() { + this(IOverlayManager.Stub.asInterface(ServiceManager.getService(Context.OVERLAY_SERVICE))); + } + + public List getOverlayInfosForTarget(String overlay, int userId) { + if (mOverlayManager == null) { + return new ArrayList<>(); + } + try { + List infos + = mOverlayManager.getOverlayInfosForTarget(overlay, userId); + ArrayList result = new ArrayList<>(infos.size()); + for (int i = 0; i < infos.size(); i++) { + result.add(new OverlayInfo(infos.get(i))); + } + return result; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public boolean setEnabled(String overlay, boolean enabled, int userId) { + if (mOverlayManager == null) { + return false; + } + try { + return mOverlayManager.setEnabled(overlay, enabled, userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public boolean setEnabledExclusiveInCategory(String overlay, int userId) { + if (mOverlayManager == null) { + return false; + } + try { + return mOverlayManager.setEnabledExclusiveInCategory(overlay, userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + public static class OverlayInfo { + + public static final String CATEGORY_THEME = android.content.om.OverlayInfo.CATEGORY_THEME; + public final String packageName; + public final String category; + private final boolean mEnabled; + + public OverlayInfo(String packageName, String category, boolean enabled) { + this.packageName = packageName; + this.category = category; + mEnabled = enabled; + } + + public OverlayInfo(android.content.om.OverlayInfo info) { + mEnabled = info.isEnabled(); + category = info.category; + packageName = info.packageName; + } + + public boolean isEnabled() { + return mEnabled; + } + } +} diff --git a/tests/robotests/src/android/content/om/IOverlayManager.java b/tests/robotests/src/android/content/om/IOverlayManager.java index 8a895e7afc4..12f7f7f8e57 100644 --- a/tests/robotests/src/android/content/om/IOverlayManager.java +++ b/tests/robotests/src/android/content/om/IOverlayManager.java @@ -16,18 +16,19 @@ package android.content.om; import android.os.IBinder; -import java.util.ArrayList; -import java.util.LinkedList; +import java.util.List; public interface IOverlayManager { - public OverlayInfo getOverlayInfo(String packageName, int userId); + OverlayInfo getOverlayInfo(String packageName, int userId); - public java.util.List getOverlayInfosForTarget(java.lang.String targetPackageName, int userId); + List getOverlayInfosForTarget(String targetPackageName, int userId); - public boolean setEnabled(java.lang.String packageName, boolean enable, int userId); + boolean setEnabled(String packageName, boolean enabled, int userId); - public static class Stub { + boolean setEnabledExclusiveInCategory(String packageName, int userId); + + class Stub { public static IOverlayManager asInterface(IBinder b) { return null; } diff --git a/tests/robotests/src/android/content/om/OverlayInfo.java b/tests/robotests/src/android/content/om/OverlayInfo.java index fb7fef1d141..d018763a9d0 100644 --- a/tests/robotests/src/android/content/om/OverlayInfo.java +++ b/tests/robotests/src/android/content/om/OverlayInfo.java @@ -15,14 +15,18 @@ package android.content.om; import android.annotation.NonNull; +import android.annotation.Nullable; public class OverlayInfo { public final String packageName; + public final String category; + public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName, - @NonNull String baseCodePath, int state, int userId) { + @Nullable String category, @NonNull String baseCodePath, int state, int userId) { this.packageName = packageName; + this.category = category; } public boolean isEnabled() { diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDashboardFragmentTest.java index 9371019fd60..3ed9717e729 100644 --- a/tests/robotests/src/com/android/settings/accounts/AccountDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accounts/AccountDashboardFragmentTest.java @@ -17,6 +17,9 @@ package com.android.settings.accounts; import static com.android.settings.accounts.AccountDashboardFragmentTest .ShadowAuthenticationHelper.LABELS; +import static com.android.settings.accounts.AccountDashboardFragmentTest + .ShadowAuthenticationHelper.TYPES; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -75,7 +78,6 @@ public class AccountDashboardFragmentTest { ShadowAuthenticationHelper.class }) public void updateSummary_hasAccount_shouldDisplayUpTo3AccountTypes() { - ShadowAuthenticationHelper.setHasAccount(true); final SummaryLoader loader = mock(SummaryLoader.class); final Activity activity = Robolectric.buildActivity(Activity.class).setup().get(); @@ -91,7 +93,7 @@ public class AccountDashboardFragmentTest { ShadowAuthenticationHelper.class }) public void updateSummary_noAccount_shouldDisplayDefaultSummary() { - ShadowAuthenticationHelper.setHasAccount(false); + ShadowAuthenticationHelper.setEnabledAccount(null); final SummaryLoader loader = mock(SummaryLoader.class); final Activity activity = Robolectric.buildActivity(Activity.class).setup().get(); @@ -103,6 +105,24 @@ public class AccountDashboardFragmentTest { activity.getString(R.string.account_dashboard_default_summary)); } + @Test + @Config(shadows = { + ShadowAuthenticationHelper.class + }) + public void updateSummary_noAccountTypeLabel_shouldNotDisplayNullEntry() { + final SummaryLoader loader = mock(SummaryLoader.class); + final Activity activity = Robolectric.buildActivity(Activity.class).setup().get(); + final String[] enabledAccounts = {TYPES[0], "unlabled_account_type", TYPES[1]}; + ShadowAuthenticationHelper.setEnabledAccount(enabledAccounts); + + final SummaryLoader.SummaryProvider provider = mFragment.SUMMARY_PROVIDER_FACTORY + .createSummaryProvider(activity, loader); + provider.setListening(true); + + // should only show the 2 accounts with labels + verify(loader).setSummary(provider, LABELS[0] + ", " + LABELS[1]); + } + @Test public void testSearchIndexProvider_shouldIndexResource() { final List indexRes = @@ -118,26 +138,25 @@ public class AccountDashboardFragmentTest { public static class ShadowAuthenticationHelper { static final String[] TYPES = new String[] {"type1", "type2", "type3", "type4"}; - static final String[] LABELS = new String[] {"LABEL1", "LABEL2", - "LABEL3", "LABEL4"}; - private static boolean sHasAccount = true; + static final String[] LABELS = new String[] {"LABEL1", "LABEL2", "LABEL3", "LABEL4"}; + private static String[] sEnabledAccount = TYPES; public void __constructor__(Context context, UserHandle userHandle, AuthenticatorHelper.OnAccountsUpdateListener listener) { } - public static void setHasAccount(boolean hasAccount) { - sHasAccount = hasAccount; + public static void setEnabledAccount(String[] enabledAccount) { + sEnabledAccount = enabledAccount; } @Resetter public static void reset() { - sHasAccount = true; + sEnabledAccount = TYPES; } @Implementation public String[] getEnabledAccountTypes() { - return sHasAccount ? TYPES : null; + return sEnabledAccount; } @Implementation @@ -151,7 +170,7 @@ public class AccountDashboardFragmentTest { } else if (TextUtils.equals(accountType, TYPES[3])) { return LABELS[3]; } - return "no_label"; + return null; } } } diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java index d721e17459f..226ea384419 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoDashboardFragmentTest.java @@ -16,6 +16,7 @@ package com.android.settings.applications.appinfo; +import static com.android.settings.applications.appinfo.AppInfoDashboardFragment.ARG_PACKAGE_NAME; import static com.android.settings.applications.appinfo.AppInfoDashboardFragment .UNINSTALL_ALL_USERS_MENU; import static com.android.settings.applications.appinfo.AppInfoDashboardFragment.UNINSTALL_UPDATES; @@ -23,6 +24,8 @@ import static com.android.settings.applications.appinfo.AppInfoDashboardFragment import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; @@ -33,18 +36,19 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; +import android.os.Bundle; import android.os.UserManager; import android.view.Menu; import android.view.MenuItem; import com.android.settings.SettingsActivity; +import com.android.settings.SettingsPreferenceFragment; import com.android.settings.TestConfig; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.wrapper.DevicePolicyManagerWrapper; @@ -57,6 +61,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; @@ -315,4 +320,37 @@ public final class AppInfoDashboardFragmentTest { verify(context).unregisterReceiver(mFragment.mPackageRemovedReceiver); } + @Test + public void startAppInfoFragment_noCrashOnNullArgs() { + final SettingsPreferenceFragment caller = mock(SettingsPreferenceFragment.class); + final SettingsActivity sa = mock (SettingsActivity.class); + when(caller.getActivity()).thenReturn(sa); + final AppEntry appEntry = mock(AppEntry.class); + appEntry.info = mock(ApplicationInfo.class); + + AppInfoDashboardFragment.startAppInfoFragment(AppInfoDashboardFragment.class, 0, null, + caller, appEntry); + } + + @Test + public void startAppInfoFragment_includesNewAndOldArgs() { + final SettingsPreferenceFragment caller = mock(SettingsPreferenceFragment.class); + final SettingsActivity sa = mock (SettingsActivity.class); + when(caller.getActivity()).thenReturn(sa); + final AppEntry appEntry = mock(AppEntry.class); + appEntry.info = mock(ApplicationInfo.class); + + final Bundle bundle = new Bundle(); + bundle.putString("test", "test"); + + AppInfoDashboardFragment.startAppInfoFragment(AppInfoDashboardFragment.class, 0, bundle, + caller, appEntry); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(Bundle.class); + verify(sa).startPreferencePanel(any(), anyString(), captor.capture(), anyInt(), any(), + any(), anyInt()); + + assertThat(captor.getValue().containsKey("test")); + assertThat(captor.getValue().containsKey(ARG_PACKAGE_NAME)); + } } diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java index 51b6ddf06d6..0c80ef42193 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppInfoPreferenceControllerBaseTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.pm.ApplicationInfo; +import android.os.Bundle; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; @@ -39,6 +40,7 @@ import com.android.settingslib.applications.ApplicationsState; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; @@ -90,9 +92,12 @@ public class AppInfoPreferenceControllerBaseTest { mController.handlePreferenceTreeClick(mPreference); + ArgumentCaptor captor = ArgumentCaptor.forClass(Bundle.class); verify(mActivity).startPreferencePanel(any(), - eq(mController.getDetailFragmentClass().getName()), any(), anyInt(), any(), any(), - anyInt()); + eq(mController.getDetailFragmentClass().getName()), captor.capture(), anyInt(), + any(), any(), anyInt()); + + assertThat(captor.getValue().containsKey("test")); } private class TestPreferenceController extends AppInfoPreferenceControllerBase { @@ -113,6 +118,13 @@ public class AppInfoPreferenceControllerBaseTest { return AppNotificationSettings.class; } + @Override + protected Bundle getArguments() { + Bundle bundle = new Bundle(); + bundle.putString("test", "test"); + return bundle; + } + } } diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java index 0b747a8f662..8dc47f81088 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppNotificationPreferenceControllerTest.java @@ -16,6 +16,8 @@ package com.android.settings.applications.appinfo; +import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -24,7 +26,9 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.Activity; import android.content.Context; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; @@ -87,4 +91,22 @@ public class AppNotificationPreferenceControllerTest { verify(mPreference).setSummary(any()); } + @Test + public void getArguments_nullIfChannelIsNull() { + assertThat(mController.getArguments()).isNull(); + } + + @Test + public void getArguments_containsChannelId() { + Activity activity = mock(Activity.class); + Intent intent = new Intent(); + intent.putExtra(EXTRA_FRAGMENT_ARG_KEY, "test"); + when(mFragment.getActivity()).thenReturn(activity); + when(activity.getIntent()).thenReturn(intent); + AppNotificationPreferenceController controller = + new AppNotificationPreferenceController(mContext, mFragment); + + assertThat(controller.getArguments().containsKey(EXTRA_FRAGMENT_ARG_KEY)).isTrue(); + assertThat(controller.getArguments().getString(EXTRA_FRAGMENT_ARG_KEY)).isEqualTo("test"); + } } diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingPreferenceControllerTest.java index 1deba785299..61987bfa76e 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingPreferenceControllerTest.java @@ -101,6 +101,6 @@ public class BluetoothPairingPreferenceControllerTest { mController.handlePreferenceTreeClick(mPreference); verify(mSettingsActivity).startPreferencePanelAsUser(eq(mFragment), anyString(), any(), - anyInt(), any(), any()); + anyInt(), any()); } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment2Test.java b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment2Test.java index 3eacd7a4f96..5aa39338fb2 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment2Test.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment2Test.java @@ -71,11 +71,6 @@ public class ConnectedDeviceDashboardFragment2Test { when(mContext.getPackageManager()).thenReturn(mManager); } - @Test - public void testCategory_isConnectedDevice() { - assertThat(mFragment.getCategoryKey()).isEqualTo(CategoryKey.CATEGORY_DEVICE); - } - @Test public void testSearchIndexProvider_shouldIndexResource() { final List indexRes = 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..91d8f7bf6c6 --- /dev/null +++ b/tests/robotests/src/com/android/settings/core/SubSettingLauncherTest.java @@ -0,0 +1,96 @@ +/* + * 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 com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; + +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)) + .setDestination(SubSettingLauncherTest.class.getName()) + .setSourceMetricsCategory(123); + doNothing().when(launcher).launch(any(Intent.class)); + launcher.launch(); + launcher.launch(); + } + + @Test(expected = IllegalArgumentException.class) + public void launch_noSourceMetricsCategory_shouldCrash() { + final SubSettingLauncher launcher = spy(new SubSettingLauncher(mContext)) + .setDestination(SubSettingLauncherTest.class.getName()); + launcher.launch(); + } + + @Test(expected = IllegalArgumentException.class) + public void launch_noDestination_shouldCrash() { + final SubSettingLauncher launcher = spy(new SubSettingLauncher(mContext)) + .setSourceMetricsCategory(123); + 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) + .setSourceMetricsCategory(123) + .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); + assertThat(intent.getIntExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY, -1)) + .isEqualTo(123); + } +} diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java index ea1d29ba370..41032bb97f8 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageSummaryPreferenceControllerTest.java @@ -16,6 +16,9 @@ package com.android.settings.datausage; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.doReturn; + import android.content.Context; import android.content.Intent; import android.net.NetworkTemplate; @@ -68,8 +71,10 @@ public class DataUsageSummaryPreferenceControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext = spy(RuntimeEnvironment.application); + doReturn("%1$s %2%s").when(mContext) + .getString(com.android.internal.R.string.fileSizeSuffix); mController = new DataUsageSummaryPreferenceController( mContext, mDataUsageController, diff --git a/tests/robotests/src/com/android/settings/development/EmulateDisplayCutoutPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/EmulateDisplayCutoutPreferenceControllerTest.java index a6af6d6cb39..64f7c8ce97f 100644 --- a/tests/robotests/src/com/android/settings/development/EmulateDisplayCutoutPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/EmulateDisplayCutoutPreferenceControllerTest.java @@ -16,27 +16,24 @@ package com.android.settings.development; -import static com.android.settings.development.EmulateDisplayCutoutPreferenceController - .EMULATION_OVERLAY_PREFIX; - import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import android.content.om.IOverlayManager; -import android.content.om.OverlayInfo; import android.content.pm.PackageManager; import android.support.v7.preference.ListPreference; +import android.view.DisplayCutout; import com.android.settings.TestConfig; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.wrapper.OverlayManagerWrapper; +import com.android.settings.wrapper.OverlayManagerWrapper.OverlayInfo; import org.junit.Before; import org.junit.Test; @@ -51,17 +48,13 @@ import java.util.Arrays; @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class EmulateDisplayCutoutPreferenceControllerTest { - static final OverlayInfo ONE_DISABLED = - new FakeOverlay(EMULATION_OVERLAY_PREFIX + ".one", false); - static final OverlayInfo ONE_ENABLED = - new FakeOverlay(EMULATION_OVERLAY_PREFIX + ".one", true); - static final OverlayInfo TWO_DISABLED = - new FakeOverlay(EMULATION_OVERLAY_PREFIX + ".two", false); - static final OverlayInfo TWO_ENABLED = - new FakeOverlay(EMULATION_OVERLAY_PREFIX + ".two", true); + static final OverlayInfo ONE_DISABLED = createFakeOverlay("emulation.one", false); + static final OverlayInfo ONE_ENABLED = createFakeOverlay("emulation.one", true); + static final OverlayInfo TWO_DISABLED = createFakeOverlay("emulation.two", false); + static final OverlayInfo TWO_ENABLED = createFakeOverlay("emulation.two", true); @Mock Context mContext; - @Mock IOverlayManager mOverlayManager; + @Mock OverlayManagerWrapper mOverlayManager; @Mock PackageManager mPackageManager; @Mock ListPreference mPreference; EmulateDisplayCutoutPreferenceController mController; @@ -101,7 +94,8 @@ public class EmulateDisplayCutoutPreferenceControllerTest { mController.onPreferenceChange(null, TWO_DISABLED.packageName); - verify(mOverlayManager).setEnabled(eq(TWO_DISABLED.packageName), eq(true), anyInt()); + verify(mOverlayManager).setEnabledExclusiveInCategory( + eq(TWO_DISABLED.packageName), anyInt()); } @Test @@ -138,7 +132,7 @@ public class EmulateDisplayCutoutPreferenceControllerTest { mController.onDeveloperOptionsSwitchEnabled(); verify(mPreference).setEnabled(true); - verify(mOverlayManager, never()).setEnabled(any(), eq(true), anyInt()); + verify(mOverlayManager, never()).setEnabledExclusiveInCategory(any(), anyInt()); } @Test @@ -156,17 +150,7 @@ public class EmulateDisplayCutoutPreferenceControllerTest { mOverlayManager); } - private static class FakeOverlay extends OverlayInfo { - private final boolean mEnabled; - - public FakeOverlay(String pkg, boolean enabled) { - super(pkg, "android", "/", 0, 0); - mEnabled = enabled; - } - - @Override - public boolean isEnabled() { - return mEnabled; - } + private static OverlayInfo createFakeOverlay(String pkg, boolean enabled) { + return new OverlayInfo(pkg, DisplayCutout.EMULATION_OVERLAY_CATEGORY, enabled); } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/display/ThemePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/ThemePreferenceControllerTest.java index 4e69b04cabd..c8f648f822a 100644 --- a/tests/robotests/src/com/android/settings/display/ThemePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/ThemePreferenceControllerTest.java @@ -33,9 +33,9 @@ import android.support.v7.preference.ListPreference; import com.android.settings.R; import com.android.settings.TestConfig; -import com.android.settings.display.ThemePreferenceController.OverlayManager; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.wrapper.OverlayManagerWrapper; import org.junit.Before; import org.junit.Test; @@ -70,7 +70,8 @@ public class ThemePreferenceControllerTest { when(mContext.getString(R.string.default_theme)) .thenReturn(RuntimeEnvironment.application.getString(R.string.default_theme)); - mController = spy(new ThemePreferenceController(mContext, mock(OverlayManager.class))); + mController = spy(new ThemePreferenceController(mContext, + mock(OverlayManagerWrapper.class))); } @Test diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java index af3a3a578a6..a188ce11f71 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java @@ -210,7 +210,7 @@ public class AdvancedPowerUsageDetailTest { }; doAnswer(callable).when(mTestActivity).startPreferencePanelAsUser( nullable(Fragment.class), nullable(String.class), captor.capture(), anyInt(), - nullable(CharSequence.class), nullable(UserHandle.class)); + nullable(UserHandle.class)); mForegroundPreference = new Preference(mContext); mBackgroundPreference = new Preference(mContext); @@ -345,7 +345,7 @@ public class AdvancedPowerUsageDetailTest { verify(mTestActivity).startPreferencePanelAsUser( nullable(Fragment.class), nullable(String.class), nullable(Bundle.class), anyInt(), - nullable(CharSequence.class), eq(new UserHandle(10))); + eq(new UserHandle(10))); } @Test @@ -361,7 +361,7 @@ public class AdvancedPowerUsageDetailTest { verify(mTestActivity).startPreferencePanelAsUser( nullable(Fragment.class), nullable(String.class), nullable(Bundle.class), anyInt(), - nullable(CharSequence.class), eq(new UserHandle(currentUser))); + eq(new UserHandle(currentUser))); } @Test @@ -372,7 +372,7 @@ public class AdvancedPowerUsageDetailTest { return null; }; doAnswer(callable).when(mTestActivity).startPreferencePanelAsUser(nullable(Fragment.class), - nullable(String.class), captor.capture(), anyInt(), nullable(CharSequence.class), + nullable(String.class), captor.capture(), anyInt(), nullable(UserHandle.class)); AdvancedPowerUsageDetail.startBatteryDetailPage(mTestActivity, null, PACKAGE_NAME[0]); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java index 92332f26822..e835e65a9b1 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryDatabaseManagerTest.java @@ -59,7 +59,7 @@ public class BatteryDatabaseManagerTest { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - mBatteryDatabaseManager = spy(new BatteryDatabaseManager(mContext)); + mBatteryDatabaseManager = spy(BatteryDatabaseManager.getInstance(mContext)); } @After diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetailsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetailsTest.java index 8aa0659671d..37b279e3ce0 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetailsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAnomalyDetailsTest.java @@ -17,8 +17,6 @@ package com.android.settings.fuelgauge; import static com.google.common.truth.Truth.assertThat; - - import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; @@ -26,7 +24,6 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; import android.content.Context; import android.content.pm.ApplicationInfo; @@ -40,9 +37,9 @@ import android.support.v7.preference.PreferenceManager; import android.util.IconDrawableFactory; import com.android.settings.SettingsActivity; -import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.fuelgauge.anomaly.Anomaly; +import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; import org.junit.Test; @@ -188,8 +185,7 @@ public class PowerUsageAnomalyDetailsTest { } }; doAnswer(bundleCallable).when(mSettingsActivity).startPreferencePanelAsUser(any(), - anyString(), - bundleCaptor.capture(), anyInt(), any(), any()); + anyString(), bundleCaptor.capture(), anyInt(), any()); PowerUsageAnomalyDetails.startBatteryAbnormalPage(mSettingsActivity, mFragment, mAnomalyList); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/RestrictAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/RestrictAppPreferenceControllerTest.java index 5e43d1d7bd5..fbcedb7d8a3 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/RestrictAppPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/RestrictAppPreferenceControllerTest.java @@ -17,7 +17,6 @@ package com.android.settings.fuelgauge; import static com.google.common.truth.Truth.assertThat; - import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; @@ -112,7 +111,7 @@ public class RestrictAppPreferenceControllerTest { verify(mSettingsActivity).startPreferencePanelAsUser(eq(mFragment), eq(RestrictedAppDetails.class.getName()), any(), eq(R.string.restricted_app_title), - any(), any()); + any()); } } diff --git a/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java index 7f495ab8e17..a3c69c5b4ed 100644 --- a/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/location/RecentLocationRequestPreferenceControllerTest.java @@ -178,7 +178,7 @@ public class RecentLocationRequestPreferenceControllerTest { verify(activity).startPreferencePanelAsUser(any(), eq(AppInfoDashboardFragment.class.getName()), - any(Bundle.class), anyInt(), any(), any()); + any(Bundle.class), anyInt(), any()); } private static ArgumentMatcher titleMatches(String expected) { diff --git a/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java b/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java index 499a2f78f34..2ffdc605aef 100644 --- a/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/DatabaseTestUtils.java @@ -19,6 +19,7 @@ package com.android.settings.testutils; import android.content.Context; import com.android.settings.fuelgauge.batterytip.AnomalyDatabaseHelper; +import com.android.settings.fuelgauge.batterytip.BatteryDatabaseManager; import com.android.settings.search.IndexDatabaseHelper; import com.android.settings.slices.SlicesDatabaseHelper; @@ -30,6 +31,7 @@ public class DatabaseTestUtils { clearSearchDb(context); clearSlicesDb(context); clearAnomalyDb(context); + clearAnomalyDbManager(); } private static void clearSlicesDb(Context context) { @@ -76,4 +78,16 @@ public class DatabaseTestUtils { throw new RuntimeException(); } } + + private static void clearAnomalyDbManager() { + Field instance; + Class clazz = BatteryDatabaseManager.class; + try { + instance = clazz.getDeclaredField("sSingleton"); + instance.setAccessible(true); + instance.set(null, null); + } catch (Exception e) { + throw new RuntimeException(); + } + } } diff --git a/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java index e9b61463c08..b20063914cf 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/WifiConfigControllerTest.java @@ -199,6 +199,15 @@ public class WifiConfigControllerTest { assertThat(mView.findViewById(R.id.eap).getVisibility()).isEqualTo(View.GONE); } + @Test + public void ssidGetFocus_addNewNetwork_shouldReturnTrue() { + mController = new TestWifiConfigController(mConfigUiBase, mView, null /* accessPoint */, + WifiConfigUiBase.MODE_CONNECT); + final TextView ssid = mView.findViewById(R.id.ssid); + // Verify ssid text get focus when add new network + assertThat(ssid.isFocused()).isTrue(); + } + public class TestWifiConfigController extends WifiConfigController { public TestWifiConfigController(WifiConfigUiBase parent, View view, diff --git a/tests/unit/src/com/android/settings/display/ThemePreferenceControllerTest.java b/tests/unit/src/com/android/settings/display/ThemePreferenceControllerTest.java index fe8203c2b72..e618343d8de 100644 --- a/tests/unit/src/com/android/settings/display/ThemePreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/display/ThemePreferenceControllerTest.java @@ -35,8 +35,7 @@ import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.support.v7.preference.ListPreference; -import com.android.settings.display.ThemePreferenceController; -import com.android.settings.display.ThemePreferenceController.OverlayManager; +import com.android.settings.wrapper.OverlayManagerWrapper; import org.junit.Before; import org.junit.Test; @@ -49,14 +48,14 @@ import java.util.ArrayList; @RunWith(AndroidJUnit4.class) public class ThemePreferenceControllerTest { - private OverlayManager mMockOverlayManager; + private OverlayManagerWrapper mMockOverlayManager; private ContextWrapper mContext; private ThemePreferenceController mPreferenceController; private PackageManager mMockPackageManager; @Before public void setup() { - mMockOverlayManager = mock(OverlayManager.class); + mMockOverlayManager = mock(OverlayManagerWrapper.class); mMockPackageManager = mock(PackageManager.class); mContext = new ContextWrapper(InstrumentationRegistry.getTargetContext()) { @Override @@ -70,9 +69,9 @@ public class ThemePreferenceControllerTest { @Test public void testUpdateState() throws Exception { OverlayInfo info1 = new OverlayInfo("com.android.Theme1", "android", - "", OverlayInfo.STATE_ENABLED, 0); + "", "", OverlayInfo.STATE_ENABLED, 0); OverlayInfo info2 = new OverlayInfo("com.android.Theme2", "android", - "", 0, 0); + "", "", 0, 0); when(mMockPackageManager.getApplicationInfo(any(), anyInt())).thenAnswer(inv -> { ApplicationInfo info = mock(ApplicationInfo.class); if ("com.android.Theme1".equals(inv.getArguments()[0])) { @@ -106,9 +105,9 @@ public class ThemePreferenceControllerTest { @Test public void testUpdateState_withStaticOverlay() throws Exception { OverlayInfo info1 = new OverlayInfo("com.android.Theme1", "android", - "", OverlayInfo.STATE_ENABLED, 0); + "", "", OverlayInfo.STATE_ENABLED, 0); OverlayInfo info2 = new OverlayInfo("com.android.Theme2", "android", - "", OverlayInfo.STATE_ENABLED, 0); + "", "", OverlayInfo.STATE_ENABLED, 0); when(mMockPackageManager.getApplicationInfo(any(), anyInt())).thenAnswer(inv -> { ApplicationInfo info = mock(ApplicationInfo.class); if ("com.android.Theme1".equals(inv.getArguments()[0])) { @@ -146,7 +145,7 @@ public class ThemePreferenceControllerTest { when(mMockPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn( new PackageInfo()); when(mMockOverlayManager.getOverlayInfosForTarget(any(), anyInt())) - .thenReturn(list(new OverlayInfo("", "", "", 0, 0))); + .thenReturn(list(new OverlayInfo("", "", "", "", 0, 0))); assertThat(mPreferenceController.isAvailable()).isFalse(); } @@ -155,15 +154,15 @@ public class ThemePreferenceControllerTest { when(mMockPackageManager.getPackageInfo(anyString(), anyInt())).thenReturn( new PackageInfo()); when(mMockOverlayManager.getOverlayInfosForTarget(any(), anyInt())) - .thenReturn(list(new OverlayInfo("", "", "", 0, 0), - new OverlayInfo("", "", "", 0, 0))); + .thenReturn(list(new OverlayInfo("", "", "", "", 0, 0), + new OverlayInfo("", "", "", "", 0, 0))); assertThat(mPreferenceController.isAvailable()).isTrue(); } - private ArrayList list(OverlayInfo... infos) { - ArrayList list = new ArrayList<>(); - for (int i = 0; i < infos.length; i++) { - list.add(infos[i]); + private ArrayList list(OverlayInfo... infos) { + ArrayList list = new ArrayList<>(); + for (OverlayInfo info : infos) { + list.add(new OverlayManagerWrapper.OverlayInfo(info)); } return list; }