diff --git a/res/layout/notification_history.xml b/res/layout/notification_history.xml index f5fae3f606f..18bb58b646d 100644 --- a/res/layout/notification_history.xml +++ b/res/layout/notification_history.xml @@ -40,7 +40,6 @@ android:layout_width="67dp" android:layout_height="67dp" android:layout_gravity="center_horizontal" - android:contentDescription="@string/notification_history" android:scaleType="fitCenter" android:focusable="false" android:tint="?android:attr/colorControlNormal" @@ -50,7 +49,6 @@ android:id="@+id/history_off_title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_below="@+id/history_image" android:layout_marginTop="48dp" android:layout_marginStart="48dp" android:layout_marginEnd="48dp" @@ -63,7 +61,6 @@ android:id="@+id/history_off_summary" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_below="@+id/history_off_title" android:layout_marginStart="48dp" android:layout_marginEnd="48dp" android:layout_marginTop="16dp" @@ -73,17 +70,33 @@ android:textAppearance="?android:attr/textAppearanceSmall" android:text="@string/notification_history_off_summary" /> + + + + @@ -98,7 +111,6 @@ android:layout_gravity="center_horizontal" android:textAlignment="center" android:focusable="true" - android:visibility="gone" android:textAppearance="?android:attr/textAppearanceSmall" android:text="@string/history_toggled_on_summary" /> diff --git a/res/xml/open_supported_links.xml b/res/xml/open_supported_links.xml index 0f6e2ca8a16..1ffec1b8045 100644 --- a/res/xml/open_supported_links.xml +++ b/res/xml/open_supported_links.xml @@ -18,17 +18,9 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/app_launch_open_domain_urls_title"> - - + android:key="supported_links_radio_group" + android:title="@string/app_link_open_always"> - \ No newline at end of file + diff --git a/src/com/android/settings/accessibility/SharedPreferenceUtils.java b/src/com/android/settings/accessibility/SharedPreferenceUtils.java index b25c3d23c35..e9972918054 100644 --- a/src/com/android/settings/accessibility/SharedPreferenceUtils.java +++ b/src/com/android/settings/accessibility/SharedPreferenceUtils.java @@ -35,7 +35,7 @@ public final class SharedPreferenceUtils { } /** Returns a set of user shortcuts list to determine user preferred service shortcut. */ - public static Set getUserShortcutType(Context context) { + public static Set getUserShortcutTypes(Context context) { return getSharedPreferences(context, ACCESSIBILITY_PERF) .getStringSet(USER_SHORTCUT_TYPE, ImmutableSet.of()); } diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java index 08be8b3d26a..547a45a495e 100644 --- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java @@ -295,7 +295,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends @Override public void onToggleClicked(ShortcutPreference preference) { - final int shortcutTypes = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); if (preference.isChecked()) { if (!mToggleServiceDividerSwitchPreference.isChecked()) { preference.setChecked(false); @@ -413,7 +413,7 @@ public class ToggleAccessibilityServicePreferenceFragment extends private void onAllowButtonFromShortcutToggleClicked() { mShortcutPreference.setChecked(true); - final int shortcutTypes = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, mComponentName); mDialog.dismiss(); diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java index 03655a5b67b..0c83ef3de4f 100644 --- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java @@ -85,7 +85,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference protected Uri mImageUri; protected CharSequence mHtmlDescription; // Used to restore the edit dialog status. - protected int mUserShortcutTypeCache = UserShortcutType.EMPTY; + protected int mUserShortcutTypesCache = UserShortcutType.EMPTY; private static final String DRAWABLE_FOLDER = "drawable"; protected static final String KEY_USE_SERVICE_PREFERENCE = "use_service"; protected static final String KEY_GENERAL_CATEGORY = "general_categories"; @@ -93,7 +93,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference private static final String KEY_SHORTCUT_PREFERENCE = "shortcut_preference"; private static final String EXTRA_SHORTCUT_TYPE = "shortcut_type"; private TouchExplorationStateChangeListener mTouchExplorationStateChangeListener; - private int mUserShortcutType = UserShortcutType.EMPTY; + private int mUserShortcutTypes = UserShortcutType.EMPTY; private CheckBox mSoftwareTypeCheckBox; private CheckBox mHardwareTypeCheckBox; @@ -233,7 +233,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference @Override public void onSaveInstanceState(Bundle outState) { - outState.putInt(EXTRA_SHORTCUT_TYPE, mUserShortcutTypeCache); + outState.putInt(EXTRA_SHORTCUT_TYPE, mUserShortcutTypesCache); super.onSaveInstanceState(outState); } @@ -474,31 +474,31 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference } private void updateAlertDialogCheckState() { - if (mUserShortcutTypeCache != UserShortcutType.EMPTY) { + if (mUserShortcutTypesCache != UserShortcutType.EMPTY) { updateCheckStatus(mSoftwareTypeCheckBox, UserShortcutType.SOFTWARE); updateCheckStatus(mHardwareTypeCheckBox, UserShortcutType.HARDWARE); } } private void updateCheckStatus(CheckBox checkBox, @UserShortcutType int type) { - checkBox.setChecked((mUserShortcutTypeCache & type) == type); + checkBox.setChecked((mUserShortcutTypesCache & type) == type); } private void updateUserShortcutType(boolean saveChanges) { - mUserShortcutTypeCache = UserShortcutType.EMPTY; + mUserShortcutTypesCache = UserShortcutType.EMPTY; if (mSoftwareTypeCheckBox.isChecked()) { - mUserShortcutTypeCache |= UserShortcutType.SOFTWARE; + mUserShortcutTypesCache |= UserShortcutType.SOFTWARE; } if (mHardwareTypeCheckBox.isChecked()) { - mUserShortcutTypeCache |= UserShortcutType.HARDWARE; + mUserShortcutTypesCache |= UserShortcutType.HARDWARE; } if (saveChanges) { - final boolean isChanged = (mUserShortcutTypeCache != UserShortcutType.EMPTY); + final boolean isChanged = (mUserShortcutTypesCache != UserShortcutType.EMPTY); if (isChanged) { - setUserShortcutType(getPrefContext(), mUserShortcutTypeCache); + setUserShortcutType(getPrefContext(), mUserShortcutTypesCache); } - mUserShortcutType = mUserShortcutTypeCache; + mUserShortcutTypes = mUserShortcutTypesCache; } } @@ -507,7 +507,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference return; } - Set info = SharedPreferenceUtils.getUserShortcutType(context); + Set info = SharedPreferenceUtils.getUserShortcutTypes(context); final String componentName = mComponentName.flattenToString(); if (info.isEmpty()) { info = new HashSet<>(); @@ -532,7 +532,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference return context.getText(R.string.switch_off_text); } - final int shortcutType = getUserShortcutType(context, UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(context, UserShortcutType.SOFTWARE); int resId = R.string.accessibility_shortcut_edit_summary_software; if (AccessibilityUtil.isGestureNavigateEnabled(context)) { resId = AccessibilityUtil.isTouchExploreEnabled(context) @@ -542,10 +542,10 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference final CharSequence softwareTitle = context.getText(resId); List list = new ArrayList<>(); - if ((shortcutType & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { + if ((shortcutTypes & UserShortcutType.SOFTWARE) == UserShortcutType.SOFTWARE) { list.add(softwareTitle); } - if ((shortcutType & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) { + if ((shortcutTypes & UserShortcutType.HARDWARE) == UserShortcutType.HARDWARE) { final CharSequence hardwareTitle = context.getText( R.string.accessibility_shortcut_edit_dialog_title_hardware); list.add(hardwareTitle); @@ -559,12 +559,12 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference return AccessibilityUtil.capitalize(joinStrings); } - protected int getUserShortcutType(Context context, @UserShortcutType int defaultValue) { + protected int getUserShortcutTypes(Context context, @UserShortcutType int defaultValue) { if (mComponentName == null) { return defaultValue; } - final Set info = SharedPreferenceUtils.getUserShortcutType(context); + final Set info = SharedPreferenceUtils.getUserShortcutTypes(context); final String componentName = mComponentName.flattenToString(); final Set filtered = info.stream() .filter(str -> str.contains(componentName)) @@ -584,11 +584,11 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference } updateUserShortcutType(/* saveChanges= */ true); - AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), mUserShortcutType, + AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), mUserShortcutTypes, mComponentName); - AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), ~mUserShortcutType, + AccessibilityUtil.optOutAllValuesFromSettings(getPrefContext(), ~mUserShortcutTypes, mComponentName); - mShortcutPreference.setChecked(mUserShortcutType != UserShortcutType.EMPTY); + mShortcutPreference.setChecked(mUserShortcutTypes != UserShortcutType.EMPTY); mShortcutPreference.setSummary( getShortcutTypeSummary(getPrefContext())); } @@ -599,20 +599,20 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference } // Get the user shortcut type from settings provider. - mUserShortcutType = AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(), + mUserShortcutTypes = AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(), mComponentName); - if (mUserShortcutType != UserShortcutType.EMPTY) { - setUserShortcutType(getPrefContext(), mUserShortcutType); + if (mUserShortcutTypes != UserShortcutType.EMPTY) { + setUserShortcutType(getPrefContext(), mUserShortcutTypes); } else { // Get the user shortcut type from shared_prefs if cannot get from settings provider. - mUserShortcutType = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + mUserShortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); } } private void initShortcutPreference(Bundle savedInstanceState) { // Restore the user shortcut type. if (savedInstanceState != null && savedInstanceState.containsKey(EXTRA_SHORTCUT_TYPE)) { - mUserShortcutTypeCache = savedInstanceState.getInt(EXTRA_SHORTCUT_TYPE, + mUserShortcutTypesCache = savedInstanceState.getInt(EXTRA_SHORTCUT_TYPE, UserShortcutType.EMPTY); } @@ -631,7 +631,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference return; } - final int shortcutTypes = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); mShortcutPreference.setChecked( AccessibilityUtil.hasValuesInSettings(getPrefContext(), shortcutTypes, mComponentName)); @@ -648,7 +648,7 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference return; } - final int shortcutTypes = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); if (preference.isChecked()) { AccessibilityUtil.optInAllValuesToSettings(getPrefContext(), shortcutTypes, mComponentName); @@ -662,8 +662,8 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference @Override public void onSettingsClicked(ShortcutPreference preference) { // Do not restore shortcut in shortcut chooser dialog when shortcutPreference is turned off. - mUserShortcutTypeCache = mShortcutPreference.isChecked() - ? getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE) + mUserShortcutTypesCache = mShortcutPreference.isChecked() + ? getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE) : UserShortcutType.EMPTY; } diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java index a9667bb54b1..91b8eaebd47 100644 --- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java @@ -192,7 +192,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends @Override public void onSaveInstanceState(Bundle outState) { - outState.putInt(EXTRA_SHORTCUT_TYPE, mUserShortcutTypeCache); + outState.putInt(EXTRA_SHORTCUT_TYPE, mUserShortcutTypesCache); super.onSaveInstanceState(outState); } @@ -281,7 +281,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends } private void updateAlertDialogCheckState() { - if (mUserShortcutTypeCache != UserShortcutType.EMPTY) { + if (mUserShortcutTypesCache != UserShortcutType.EMPTY) { updateCheckStatus(mSoftwareTypeCheckBox, UserShortcutType.SOFTWARE); updateCheckStatus(mHardwareTypeCheckBox, UserShortcutType.HARDWARE); updateCheckStatus(mTripleTapTypeCheckBox, UserShortcutType.TRIPLETAP); @@ -289,32 +289,32 @@ public class ToggleScreenMagnificationPreferenceFragment extends } private void updateCheckStatus(CheckBox checkBox, @UserShortcutType int type) { - checkBox.setChecked((mUserShortcutTypeCache & type) == type); + checkBox.setChecked((mUserShortcutTypesCache & type) == type); } private void updateUserShortcutType(boolean saveChanges) { - mUserShortcutTypeCache = UserShortcutType.EMPTY; + mUserShortcutTypesCache = UserShortcutType.EMPTY; if (mSoftwareTypeCheckBox.isChecked()) { - mUserShortcutTypeCache |= UserShortcutType.SOFTWARE; + mUserShortcutTypesCache |= UserShortcutType.SOFTWARE; } if (mHardwareTypeCheckBox.isChecked()) { - mUserShortcutTypeCache |= UserShortcutType.HARDWARE; + mUserShortcutTypesCache |= UserShortcutType.HARDWARE; } if (mTripleTapTypeCheckBox.isChecked()) { - mUserShortcutTypeCache |= UserShortcutType.TRIPLETAP; + mUserShortcutTypesCache |= UserShortcutType.TRIPLETAP; } if (saveChanges) { - final boolean isChanged = (mUserShortcutTypeCache != UserShortcutType.EMPTY); + final boolean isChanged = (mUserShortcutTypesCache != UserShortcutType.EMPTY); if (isChanged) { - setUserShortcutType(getPrefContext(), mUserShortcutTypeCache); + setUserShortcutType(getPrefContext(), mUserShortcutTypesCache); } - mUserShortcutType = mUserShortcutTypeCache; + mUserShortcutType = mUserShortcutTypesCache; } } private void setUserShortcutType(Context context, int type) { - Set info = SharedPreferenceUtils.getUserShortcutType(context); + Set info = SharedPreferenceUtils.getUserShortcutTypes(context); if (info.isEmpty()) { info = new HashSet<>(); } else { @@ -335,7 +335,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends return context.getText(R.string.switch_off_text); } - final int shortcutType = getUserShortcutType(context, UserShortcutType.EMPTY); + final int shortcutType = getUserShortcutTypes(context, UserShortcutType.EMPTY); int resId = R.string.accessibility_shortcut_edit_summary_software; if (AccessibilityUtil.isGestureNavigateEnabled(context)) { resId = AccessibilityUtil.isTouchExploreEnabled(context) @@ -369,8 +369,8 @@ public class ToggleScreenMagnificationPreferenceFragment extends } @Override - protected int getUserShortcutType(Context context, @UserShortcutType int defaultValue) { - final Set info = SharedPreferenceUtils.getUserShortcutType(context); + protected int getUserShortcutTypes(Context context, @UserShortcutType int defaultValue) { + final Set info = SharedPreferenceUtils.getUserShortcutTypes(context); final Set filtered = info.stream().filter( str -> str.contains(MAGNIFICATION_CONTROLLER_NAME)).collect( Collectors.toSet()); @@ -446,7 +446,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends @Override public void onToggleClicked(ShortcutPreference preference) { - final int shortcutTypes = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); if (preference.isChecked()) { optInAllMagnificationValuesToSettings(getPrefContext(), shortcutTypes); } else { @@ -458,8 +458,8 @@ public class ToggleScreenMagnificationPreferenceFragment extends @Override public void onSettingsClicked(ShortcutPreference preference) { // Do not restore shortcut in shortcut chooser dialog when shortcutPreference is turned off. - mUserShortcutTypeCache = mShortcutPreference.isChecked() - ? getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE) + mUserShortcutTypesCache = mShortcutPreference.isChecked() + ? getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE) : UserShortcutType.EMPTY; showDialog(DialogEnums.MAGNIFICATION_EDIT_SHORTCUT); } @@ -471,7 +471,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends setUserShortcutType(getPrefContext(), mUserShortcutType); } else { // Get the user shortcut type from shared_prefs if cannot get from settings provider. - mUserShortcutType = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + mUserShortcutType = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); } } @@ -487,7 +487,7 @@ public class ToggleScreenMagnificationPreferenceFragment extends } private void updateShortcutPreference() { - final int shortcutTypes = getUserShortcutType(getPrefContext(), UserShortcutType.SOFTWARE); + final int shortcutTypes = getUserShortcutTypes(getPrefContext(), UserShortcutType.SOFTWARE); mShortcutPreference.setChecked( hasMagnificationValuesInSettings(getPrefContext(), shortcutTypes)); mShortcutPreference.setSummary(getShortcutTypeSummary(getPrefContext())); diff --git a/src/com/android/settings/applications/AppHeaderPreferenceController.java b/src/com/android/settings/applications/AppHeaderPreferenceController.java deleted file mode 100644 index 0f473e7f08c..00000000000 --- a/src/com/android/settings/applications/AppHeaderPreferenceController.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2020 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.applications; - -import static com.android.settings.widget.EntityHeaderController.ActionType; - -import android.app.Activity; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; - -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.core.BasePreferenceController; -import com.android.settings.dashboard.DashboardFragment; -import com.android.settings.widget.EntityHeaderController; -import com.android.settingslib.applications.AppUtils; -import com.android.settingslib.core.lifecycle.Lifecycle; -import com.android.settingslib.core.lifecycle.LifecycleObserver; -import com.android.settingslib.core.lifecycle.events.OnResume; -import com.android.settingslib.widget.LayoutPreference; - -/** - * The header controller displays on the top of the page. - */ -public class AppHeaderPreferenceController extends BasePreferenceController implements - LifecycleObserver, OnResume { - private DashboardFragment mParent; - private PackageInfo mPackageInfo; - private Lifecycle mLifecycle; - private LayoutPreference mHeaderPreference; - - public AppHeaderPreferenceController(Context context, String preferenceKey) { - super(context, preferenceKey); - } - - /** - * @param fragment set the parent fragment. - * @return return controller-self. - */ - public AppHeaderPreferenceController setParentFragment(DashboardFragment fragment) { - mParent = fragment; - return this; - } - - /** - * @param packageInfo set the {@link PackageInfo}. - * @return return controller-self. - */ - public AppHeaderPreferenceController setPackageInfo(PackageInfo packageInfo) { - mPackageInfo = packageInfo; - return this; - } - - /** - * @param lifeCycle set the {@link Lifecycle}. - * @return return controller-self. - */ - public AppHeaderPreferenceController setLifeCycle(Lifecycle lifeCycle) { - mLifecycle = lifeCycle; - return this; - } - - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - mHeaderPreference = screen.findPreference(getPreferenceKey()); - } - - @Override - public int getAvailabilityStatus() { - return AVAILABLE; - } - - @Override - public void onResume() { - final Activity activity = mParent.getActivity(); - final PackageManager packageManager = activity.getPackageManager(); - EntityHeaderController - .newInstance(activity, mParent, mHeaderPreference.findViewById(R.id.entity_header)) - .setRecyclerView(mParent.getListView(), mLifecycle) - .setIcon(Utils.getBadgedIcon(mParent.getContext(), mPackageInfo.applicationInfo)) - .setLabel(mPackageInfo.applicationInfo.loadLabel(packageManager)) - .setSummary(mPackageInfo) - .setIsInstantApp(AppUtils.isInstant(mPackageInfo.applicationInfo)) - .setPackageName(mPackageInfo.packageName) - .setUid(mPackageInfo.applicationInfo.uid) - .setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE) - .done(mParent.getActivity(), true /* rebindActions */); - } -} diff --git a/src/com/android/settings/applications/AppLaunchSettings.java b/src/com/android/settings/applications/AppLaunchSettings.java index 17d8e67a0bb..fdd2d16cec9 100644 --- a/src/com/android/settings/applications/AppLaunchSettings.java +++ b/src/com/android/settings/applications/AppLaunchSettings.java @@ -28,7 +28,6 @@ import android.net.Uri; import android.os.Bundle; import android.os.UserHandle; import android.util.ArraySet; -import android.util.Log; import android.view.View; import android.view.View.OnClickListener; @@ -50,8 +49,6 @@ public class AppLaunchSettings extends AppInfoWithHeader implements OnClickListe private static final String FRAGMENT_OPEN_SUPPORTED_LINKS = "com.android.settings.applications.OpenSupportedLinks"; - public static final String KEY_PACKAGE_INFO = "pkg_info"; - private static final Intent sBrowserIntent; static { @@ -79,7 +76,8 @@ public class AppLaunchSettings extends AppInfoWithHeader implements OnClickListe mAppLinkState = findPreference(KEY_APP_LINK_STATE); mAppLinkState.setOnPreferenceClickListener(preference -> { final Bundle args = new Bundle(); - args.putParcelable(KEY_PACKAGE_INFO, this.mPackageInfo); + args.putString(ARG_PACKAGE_NAME, mPackageName); + args.putInt(ARG_PACKAGE_UID, mUserId); new SubSettingLauncher(this.getContext()) .setDestination(FRAGMENT_OPEN_SUPPORTED_LINKS) @@ -145,7 +143,6 @@ public class AppLaunchSettings extends AppInfoWithHeader implements OnClickListe private void setAppLinkStateSummary() { final int state = mPm.getIntentVerificationStatusAsUser(mPackageName, UserHandle.myUserId()); - Log.d("[sunny]", "setAppLinkStateSummary+ state=" + state); mAppLinkState.setSummary(linkStateToResourceId(state)); } diff --git a/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceController.java b/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceController.java deleted file mode 100644 index 479d5dd0b04..00000000000 --- a/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceController.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2020 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.applications; - -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.UserHandle; -import android.text.TextUtils; -import android.util.Log; -import android.view.View; - -import androidx.annotation.VisibleForTesting; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.Utils; -import com.android.settings.core.BasePreferenceController; -import com.android.settingslib.widget.RadioButtonPreference; - -/** - * The radio group controller supports users to choose what kind supported links they need. - */ -public class AppOpenSupportedLinksPreferenceController extends BasePreferenceController - implements RadioButtonPreference.OnClickListener { - private static final String TAG = "OpenLinksPrefCtrl"; - private static final String KEY_LINK_OPEN_ALWAYS = "app_link_open_always"; - private static final String KEY_LINK_OPEN_ASK = "app_link_open_ask"; - private static final String KEY_LINK_OPEN_NEVER = "app_link_open_never"; - - private Context mContext; - private PackageManager mPackageManager; - private String mPackageName; - private int mCurrentIndex; - private PreferenceCategory mPreferenceCategory; - private String[] mRadioKeys = {KEY_LINK_OPEN_ALWAYS, KEY_LINK_OPEN_ASK, KEY_LINK_OPEN_NEVER}; - - @VisibleForTesting - RadioButtonPreference mAllowOpening; - @VisibleForTesting - RadioButtonPreference mAskEveryTime; - @VisibleForTesting - RadioButtonPreference mNotAllowed; - - public AppOpenSupportedLinksPreferenceController(Context context, String preferenceKey) { - super(context, preferenceKey); - mContext = context; - mPackageManager = context.getPackageManager(); - } - - /** - * @param pkg selected package name. - * @return return controller-self. - */ - public AppOpenSupportedLinksPreferenceController setInit(String pkg) { - mPackageName = pkg; - return this; - } - - @Override - public void displayPreference(PreferenceScreen screen) { - super.displayPreference(screen); - mPreferenceCategory = screen.findPreference(getPreferenceKey()); - mAllowOpening = makeRadioPreference(KEY_LINK_OPEN_ALWAYS, R.string.app_link_open_always); - final int entriesNo = getEntriesNo(); - //This to avoid the summary line wrap - mAllowOpening.setAppendixVisibility(View.GONE); - mAllowOpening.setSummary( - mContext.getResources().getQuantityString(R.plurals.app_link_open_always_summary, - entriesNo, entriesNo)); - mAskEveryTime = makeRadioPreference(KEY_LINK_OPEN_ASK, R.string.app_link_open_ask); - mNotAllowed = makeRadioPreference(KEY_LINK_OPEN_NEVER, R.string.app_link_open_never); - - final int state = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, - UserHandle.myUserId()); - mCurrentIndex = linkStateToIndex(state); - setRadioStatus(mCurrentIndex); - } - - @Override - public int getAvailabilityStatus() { - return AVAILABLE; - } - - @Override - public void onRadioButtonClicked(RadioButtonPreference preference) { - final int clickedIndex = preferenceKeyToIndex(preference.getKey()); - if (mCurrentIndex != clickedIndex) { - mCurrentIndex = clickedIndex; - setRadioStatus(mCurrentIndex); - updateAppLinkState(indexToLinkState(mCurrentIndex)); - } - } - - private RadioButtonPreference makeRadioPreference(String key, int resourceId) { - RadioButtonPreference pref = new RadioButtonPreference(mPreferenceCategory.getContext()); - pref.setKey(key); - pref.setTitle(resourceId); - pref.setOnClickListener(this); - mPreferenceCategory.addPreference(pref); - return pref; - } - - private int linkStateToIndex(int state) { - switch (state) { - case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: - return 0; // Always - case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: - return 2; // Never - default: - return 1; // Ask - } - } - - private int indexToLinkState(int index) { - switch (index) { - case 0: - return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; - case 2: - return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; - default: - return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; - } - } - - private int preferenceKeyToIndex(String key) { - for (int i = 0; i < mRadioKeys.length; i++) { - if (TextUtils.equals(key, mRadioKeys[i])) { - return i; - } - } - return 1; // Ask - } - - private void setRadioStatus(int index) { - mAllowOpening.setChecked(index == 0 ? true : false); - mAskEveryTime.setChecked(index == 1 ? true : false); - mNotAllowed.setChecked(index == 2 ? true : false); - } - - private boolean updateAppLinkState(final int newState) { - final int userId = UserHandle.myUserId(); - final int priorState = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, - userId); - - if (priorState == newState) { - return false; - } - - boolean success = mPackageManager.updateIntentVerificationStatusAsUser(mPackageName, - newState, userId); - if (success) { - // Read back the state to see if the change worked - final int updatedState = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, - userId); - success = (newState == updatedState); - } else { - Log.e(TAG, "Couldn't update intent verification status!"); - } - return success; - } - - @VisibleForTesting - int getEntriesNo() { - return Utils.getHandledDomains(mPackageManager, mPackageName).size(); - } -} diff --git a/src/com/android/settings/applications/OpenSupportedLinks.java b/src/com/android/settings/applications/OpenSupportedLinks.java index 0e1531f8d0c..84b03f173d1 100644 --- a/src/com/android/settings/applications/OpenSupportedLinks.java +++ b/src/com/android/settings/applications/OpenSupportedLinks.java @@ -15,48 +15,176 @@ */ package com.android.settings.applications; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; + import android.app.settings.SettingsEnums; -import android.content.Context; -import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.os.Bundle; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import android.view.View; import androidx.annotation.VisibleForTesting; +import androidx.appcompat.app.AlertDialog; +import androidx.preference.PreferenceCategory; import com.android.settings.R; import com.android.settings.Utils; -import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.widget.FooterPreference; +import com.android.settingslib.widget.RadioButtonPreference; /** * Display the Open Supported Links page. Allow users choose what kind supported links they need. */ -public class OpenSupportedLinks extends DashboardFragment { +public class OpenSupportedLinks extends AppInfoWithHeader implements + RadioButtonPreference.OnClickListener { private static final String TAG = "OpenSupportedLinks"; + private static final String RADIO_GROUP_KEY = "supported_links_radio_group"; private static final String FOOTER_KEY = "supported_links_footer"; + private static final String KEY_LINK_OPEN_ALWAYS = "app_link_open_always"; + private static final String KEY_LINK_OPEN_ASK = "app_link_open_ask"; + private static final String KEY_LINK_OPEN_NEVER = "app_link_open_never"; + + private static final int ALLOW_ALWAYS_OPENING = 0; + private static final int ASK_EVERY_TIME = 1; + private static final int NOT_ALLOWED_OPENING = 2; + + private int mCurrentIndex; + private String[] mRadioKeys = {KEY_LINK_OPEN_ALWAYS, KEY_LINK_OPEN_ASK, KEY_LINK_OPEN_NEVER}; @VisibleForTesting - PackageInfo mPackageInfo; + PackageManager mPackageManager; + @VisibleForTesting + PreferenceCategory mPreferenceCategory; + @VisibleForTesting + RadioButtonPreference mAllowOpening; + @VisibleForTesting + RadioButtonPreference mAskEveryTime; + @VisibleForTesting + RadioButtonPreference mNotAllowed; @Override - public void onAttach(Context context) { - super.onAttach(context); - final Bundle args = getArguments(); - mPackageInfo = (args != null) ? args.getParcelable(AppLaunchSettings.KEY_PACKAGE_INFO) - : null; - if (mPackageInfo == null) { - Log.w(TAG, "Missing PackageInfo; maybe reinstalling?"); - return; - } - use(AppHeaderPreferenceController.class).setParentFragment(this).setPackageInfo( - mPackageInfo).setLifeCycle(getSettingsLifecycle()); - use(AppOpenSupportedLinksPreferenceController.class).setInit(mPackageInfo.packageName); + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mPackageManager = getPackageManager(); + addPreferencesFromResource(R.xml.open_supported_links); + initRadioPreferencesGroup(); + updateFooterPreference(); } @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - super.onCreatePreferences(savedInstanceState, rootKey); + public int getMetricsCategory() { + return SettingsEnums.OPEN_SUPPORTED_LINKS; + } + + /** + * Here to handle radio group and generate the radios. + */ + @VisibleForTesting + void initRadioPreferencesGroup() { + mPreferenceCategory = findPreference(RADIO_GROUP_KEY); + mAllowOpening = makeRadioPreference(KEY_LINK_OPEN_ALWAYS, R.string.app_link_open_always); + final int entriesNo = getEntriesNo(); + //This to avoid the summary line wrap + mAllowOpening.setAppendixVisibility(View.GONE); + mAllowOpening.setSummary(getResources().getQuantityString( + R.plurals.app_link_open_always_summary, entriesNo, entriesNo)); + mAskEveryTime = makeRadioPreference(KEY_LINK_OPEN_ASK, R.string.app_link_open_ask); + mNotAllowed = makeRadioPreference(KEY_LINK_OPEN_NEVER, R.string.app_link_open_never); + + final int state = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, mUserId); + mCurrentIndex = linkStateToIndex(state); + setRadioStatus(mCurrentIndex); + } + + @Override + public void onRadioButtonClicked(RadioButtonPreference preference) { + final int clickedIndex = preferenceKeyToIndex(preference.getKey()); + if (mCurrentIndex != clickedIndex) { + mCurrentIndex = clickedIndex; + setRadioStatus(mCurrentIndex); + updateAppLinkState(indexToLinkState(mCurrentIndex)); + } + } + + private RadioButtonPreference makeRadioPreference(String key, int stringId) { + final RadioButtonPreference pref = new RadioButtonPreference( + mPreferenceCategory.getContext()); + pref.setKey(key); + pref.setTitle(stringId); + pref.setOnClickListener(this); + mPreferenceCategory.addPreference(pref); + return pref; + } + + @VisibleForTesting + int getEntriesNo() { + return Utils.getHandledDomains(mPackageManager, mPackageName).size(); + } + + private int linkStateToIndex(int state) { + switch (state) { + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: + return ALLOW_ALWAYS_OPENING; + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: + return NOT_ALLOWED_OPENING; + default: + return ASK_EVERY_TIME; + } + } + + private int indexToLinkState(int index) { + switch (index) { + case 0: + return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; + case 2: + return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; + default: + return INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; + } + } + + private void setRadioStatus(int index) { + mAllowOpening.setChecked(index == ALLOW_ALWAYS_OPENING); + mAskEveryTime.setChecked(index == ASK_EVERY_TIME); + mNotAllowed.setChecked(index == NOT_ALLOWED_OPENING); + } + + private int preferenceKeyToIndex(String key) { + for (int i = 0; i < mRadioKeys.length; i++) { + if (TextUtils.equals(key, mRadioKeys[i])) { + return i; + } + } + return ASK_EVERY_TIME; + } + + private void updateAppLinkState(final int newState) { + final int priorState = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, + mUserId); + + if (priorState == newState) { + return; + } + + final boolean success = mPackageManager.updateIntentVerificationStatusAsUser(mPackageName, + newState, mUserId); + if (success) { + // Read back the state to see if the change worked + final int updatedState = mPackageManager.getIntentVerificationStatusAsUser(mPackageName, + mUserId); + } else { + Log.e(TAG, "Couldn't update intent verification status!"); + } + } + + /** + * Here is handle the Footer. + */ + private void updateFooterPreference() { final FooterPreference footer = findPreference(FOOTER_KEY); if (footer == null) { Log.w(TAG, "Can't find the footer preference."); @@ -65,25 +193,9 @@ public class OpenSupportedLinks extends DashboardFragment { addLinksToFooter(footer); } - @Override - protected int getPreferenceScreenResId() { - return R.xml.open_supported_links; - } - - @Override - protected String getLogTag() { - return TAG; - } - - @Override - public int getMetricsCategory() { - return SettingsEnums.OPEN_SUPPORTED_LINKS; - } - @VisibleForTesting void addLinksToFooter(FooterPreference footer) { - final ArraySet result = Utils.getHandledDomains(getPackageManager(), - mPackageInfo.packageName); + final ArraySet result = Utils.getHandledDomains(mPackageManager, mPackageName); if (result.isEmpty()) { Log.w(TAG, "Can't find any app links."); return; @@ -94,4 +206,14 @@ public class OpenSupportedLinks extends DashboardFragment { } footer.setTitle(title); } + + @Override + protected boolean refreshUi() { + return true; + } + + @Override + protected AlertDialog createDialog(int id, int errorCode) { + return null; + } } diff --git a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java index c1afb772427..5343709208e 100644 --- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java @@ -474,10 +474,28 @@ public class EnabledNetworkModePreferenceController extends } } break; - case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO: + + case TelephonyManagerConstants.NETWORK_MODE_NR_ONLY: + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE: case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA: + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_WCDMA: + setSelectedEntry( + TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA); + setSummary(mContext.getString(R.string.network_5G) + + mContext.getString(R.string.network_recommended)); + break; + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA: + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM: + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_WCDMA: + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM_WCDMA: case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA: - setSelectedEntry(networkMode); + setSelectedEntry( + TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA); + setSummary(mContext.getString(R.string.network_5G) + + mContext.getString(R.string.network_recommended)); + break; + case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO: + setSelectedEntry(TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO); setSummary(mContext.getString(R.string.network_5G) + mContext.getString(R.string.network_recommended)); break; diff --git a/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java b/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java index cbe0912f0e9..0471f74c717 100644 --- a/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java +++ b/src/com/android/settings/network/telephony/Enhanced4gBasePreferenceController.java @@ -16,7 +16,10 @@ package com.android.settings.network.telephony; +import android.app.AlertDialog; +import android.app.Dialog; import android.content.Context; +import android.content.DialogInterface; import android.os.Looper; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; @@ -31,6 +34,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; +import com.android.settings.R; import com.android.settings.network.ims.VolteQueryImsState; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; @@ -50,6 +54,8 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc @VisibleForTesting Preference mPreference; private PhoneCallStateListener mPhoneStateListener; + private boolean mShow5gLimitedDialog; + private boolean mHas5gCapability; @VisibleForTesting Integer mCallState; private final List m4gLteListeners; @@ -83,6 +89,9 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc if (m4gCurrentMode != MODE_ADVANCED_CALL) { m4gCurrentMode = show4GForLTE ? MODE_4G_CALLING : MODE_VOLTE; } + + mShow5gLimitedDialog = carrierConfig.getBoolean( + CarrierConfigManager.KEY_VOLTE_5G_LIMITED_ALERT_DIALOG_BOOL); return this; } @@ -142,16 +151,13 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc if (imsMmTelManager == null) { return false; } - try { - imsMmTelManager.setAdvancedCallingSettingEnabled(isChecked); - } catch (IllegalArgumentException exception) { - Log.w(TAG, "fail to set VoLTE=" + isChecked + ". subId=" + mSubId, exception); - return false; + + if (isDialogNeeded() && !isChecked) { + show5gLimitedDialog(imsMmTelManager); + } else { + return setAdvancedCallingSettingEnabled(imsMmTelManager, isChecked); } - for (final On4gLteUpdateListener lsn : m4gLteListeners) { - lsn.on4gLteUpdated(); - } - return true; + return false; } @Override @@ -205,6 +211,10 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId); } mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE); + + final long supportedRadioBitmask = mTelephonyManager.getSupportedRadioAccessFamily(); + mHas5gCapability = + (supportedRadioBitmask & TelephonyManager.NETWORK_TYPE_BITMASK_NR) > 0; } public void unregister() { @@ -219,4 +229,46 @@ public class Enhanced4gBasePreferenceController extends TelephonyTogglePreferenc public interface On4gLteUpdateListener { void on4gLteUpdated(); } + + private boolean isDialogNeeded() { + Log.d(TAG, "Has5gCapability:" + mHas5gCapability); + return mShow5gLimitedDialog && mHas5gCapability; + } + + private void show5gLimitedDialog(ImsMmTelManager imsMmTelManager) { + Log.d(TAG, "show5gLimitedDialog"); + AlertDialog.Builder builder = new AlertDialog.Builder(mContext); + DialogInterface.OnClickListener networkSettingsClickListener = + new Dialog.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + Log.d(TAG, "onClick,isChecked:false"); + setAdvancedCallingSettingEnabled(imsMmTelManager, false); + updateState(mPreference); + } + }; + builder.setTitle(R.string.volte_5G_limited_title) + .setMessage(R.string.volte_5G_limited_text) + .setNeutralButton(mContext.getResources().getString( + R.string.cancel), null) + .setPositiveButton(mContext.getResources().getString( + R.string.condition_turn_off), + networkSettingsClickListener) + .create() + .show(); + } + + private boolean setAdvancedCallingSettingEnabled(ImsMmTelManager imsMmTelManager, + boolean isChecked) { + try { + imsMmTelManager.setAdvancedCallingSettingEnabled(isChecked); + } catch (IllegalArgumentException exception) { + Log.w(TAG, "fail to set VoLTE=" + isChecked + ". subId=" + mSubId, exception); + return false; + } + for (final On4gLteUpdateListener lsn : m4gLteListeners) { + lsn.on4gLteUpdated(); + } + return true; + } } diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java index 746a2df8ab2..6c2016bb940 100644 --- a/src/com/android/settings/notification/SoundSettings.java +++ b/src/com/android/settings/notification/SoundSettings.java @@ -76,6 +76,7 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult private RingtonePreference mRequestPreference; private UpdatableListPreferenceDialogFragment mDialogFragment; private String mHfpOutputControllerKey; + private String mVibrationPreferencesKey = "vibration_preference_screen"; @Override public int getMetricsCategory() { @@ -127,6 +128,10 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult @Override public void onDisplayPreferenceDialog(Preference preference) { + if (TextUtils.equals(mVibrationPreferencesKey, preference.getKey())) { + super.onDisplayPreferenceDialog(preference); + return; + } final int metricsCategory; if (mHfpOutputControllerKey.equals(preference.getKey())) { metricsCategory = SettingsEnums.DIALOG_SWITCH_HFP_DEVICES; @@ -311,4 +316,4 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult mDialogFragment.onListPreferenceUpdated(preference); } } -} \ No newline at end of file +} diff --git a/src/com/android/settings/notification/history/NotificationHistoryActivity.java b/src/com/android/settings/notification/history/NotificationHistoryActivity.java index 73befeb4801..144d102e651 100644 --- a/src/com/android/settings/notification/history/NotificationHistoryActivity.java +++ b/src/com/android/settings/notification/history/NotificationHistoryActivity.java @@ -22,15 +22,11 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.INotificationManager; import android.content.ComponentName; -import android.content.ContentResolver; import android.content.Context; import android.content.pm.PackageManager; -import android.database.ContentObserver; -import android.net.Uri; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; -import android.os.UserHandle; import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; @@ -50,9 +46,13 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.settings.R; import com.android.settings.notification.NotificationBackend; import com.android.settings.widget.SwitchBar; +import com.android.settingslib.utils.ThreadUtils; import java.util.ArrayList; import java.util.Arrays; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; public class NotificationHistoryActivity extends Activity { @@ -60,18 +60,22 @@ public class NotificationHistoryActivity extends Activity { private ViewGroup mHistoryOn; private ViewGroup mHistoryOff; + private ViewGroup mHistoryEmpty; private ViewGroup mTodayView; private ViewGroup mSnoozeView; private ViewGroup mDismissView; + private SwitchBar mSwitchBar; - private SettingsObserver mSettingsObserver = new SettingsObserver(); private HistoryLoader mHistoryLoader; private INotificationManager mNm; private PackageManager mPm; + private CountDownLatch mCountdownLatch; + private Future mCountdownFuture; private HistoryLoader.OnHistoryLoaderListener mOnHistoryLoaderListener = notifications -> { findViewById(R.id.today_list).setVisibility( notifications.isEmpty() ? View.GONE : View.VISIBLE); + mCountdownLatch.countDown(); // for each package, new header and recycler view for (NotificationHistoryPackage nhp : notifications) { View viewForPackage = LayoutInflater.from(this) @@ -124,6 +128,8 @@ public class NotificationHistoryActivity extends Activity { mDismissView = findViewById(R.id.recently_dismissed_list); mHistoryOff = findViewById(R.id.history_off); mHistoryOn = findViewById(R.id.history_on); + mHistoryEmpty = findViewById(R.id.history_on_empty); + mSwitchBar = findViewById(R.id.switch_bar); } @Override @@ -131,6 +137,8 @@ public class NotificationHistoryActivity extends Activity { super.onResume(); mPm = getPackageManager(); + // wait for history loading and recent/snooze loading + mCountdownLatch = new CountDownLatch(2); mTodayView.removeAllViews(); mHistoryLoader = new HistoryLoader(this, new NotificationBackend(), mPm); @@ -144,9 +152,25 @@ public class NotificationHistoryActivity extends Activity { } catch (RemoteException e) { Log.e(TAG, "Cannot register listener", e); } - mSettingsObserver.observe(); bindSwitch(); + + mCountdownFuture = ThreadUtils.postOnBackgroundThread(() -> { + try { + mCountdownLatch.await(2, TimeUnit.SECONDS); + } catch (InterruptedException e) { + Slog.e(TAG, "timed out waiting for loading", e); + } + ThreadUtils.postOnMainThread(() -> { + if (mSwitchBar.isChecked() + && findViewById(R.id.today_list).getVisibility() == View.GONE + && mSnoozeView.getVisibility() == View.GONE + && mDismissView.getVisibility() == View.GONE) { + mHistoryOn.setVisibility(View.GONE); + mHistoryEmpty.setVisibility(View.VISIBLE); + } + }); + }); } @Override @@ -156,24 +180,30 @@ public class NotificationHistoryActivity extends Activity { } catch (RemoteException e) { Log.e(TAG, "Cannot unregister listener", e); } - mSettingsObserver.stopObserving(); super.onPause(); } + @Override + public void onDestroy() { + if (mCountdownFuture != null) { + mCountdownFuture.cancel(true); + } + super.onDestroy(); + } + private void bindSwitch() { - SwitchBar bar = findViewById(R.id.switch_bar); - if (bar != null) { - bar.setSwitchBarText(R.string.notification_history_toggle, + if (mSwitchBar != null) { + mSwitchBar.setSwitchBarText(R.string.notification_history_toggle, R.string.notification_history_toggle); - bar.show(); + mSwitchBar.show(); try { - bar.addOnSwitchChangeListener(mOnSwitchClickListener); + mSwitchBar.addOnSwitchChangeListener(mOnSwitchClickListener); } catch (IllegalStateException e) { // an exception is thrown if you try to add the listener twice } - bar.setChecked(Settings.Secure.getInt(getContentResolver(), + mSwitchBar.setChecked(Settings.Secure.getInt(getContentResolver(), NOTIFICATION_HISTORY_ENABLED, 0) == 1); - toggleViews(bar.isChecked()); + toggleViews(mSwitchBar.isChecked()); } } @@ -184,53 +214,9 @@ public class NotificationHistoryActivity extends Activity { } else { mHistoryOn.setVisibility(View.GONE); mHistoryOff.setVisibility(View.VISIBLE); - mHistoryOff.findViewById(R.id.history_off_title).setVisibility(View.VISIBLE); - mHistoryOff.findViewById(R.id.history_off_summary).setVisibility(View.VISIBLE); - mHistoryOff.findViewById(R.id.history_toggled_on_title).setVisibility(View.GONE); - mHistoryOff.findViewById(R.id.history_toggled_on_summary).setVisibility(View.GONE); mTodayView.removeAllViews(); } - } - - private void onHistoryEnabledChanged(boolean enabled) { - if (enabled) { - mHistoryLoader.load(mOnHistoryLoaderListener); - } - } - - final class SettingsObserver extends ContentObserver { - private final Uri NOTIFICATION_HISTORY_URI - = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_HISTORY_ENABLED); - - SettingsObserver() { - super(null); - } - - void observe() { - ContentResolver resolver = getContentResolver(); - resolver.registerContentObserver(NOTIFICATION_HISTORY_URI, - false, this, UserHandle.USER_ALL); - } - - void stopObserving() { - ContentResolver resolver = getContentResolver(); - resolver.unregisterContentObserver(this); - } - - @Override - public void onChange(boolean selfChange, Uri uri) { - update(uri); - } - - public void update(Uri uri) { - ContentResolver resolver = getContentResolver(); - if (uri == null || NOTIFICATION_HISTORY_URI.equals(uri)) { - boolean historyEnabled = Settings.Secure.getInt(resolver, - Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0) - != 0; - onHistoryEnabledChanged(historyEnabled); - } - } + mHistoryEmpty.setVisibility(View.GONE); } private final SwitchBar.OnSwitchChangeListener mOnSwitchClickListener = @@ -239,16 +225,14 @@ public class NotificationHistoryActivity extends Activity { NOTIFICATION_HISTORY_ENABLED, isChecked ? 1 : 0); mHistoryOn.setVisibility(View.GONE); - mHistoryOff.findViewById(R.id.history_off_title).setVisibility( - isChecked ? View.GONE : View.VISIBLE); - mHistoryOff.findViewById(R.id.history_off_summary).setVisibility( - isChecked ? View.GONE : View.VISIBLE); - mHistoryOff.findViewById(R.id.history_toggled_on_title).setVisibility( - isChecked ? View.VISIBLE : View.GONE); - mHistoryOff.findViewById(R.id.history_toggled_on_summary).setVisibility( - isChecked ? View.VISIBLE : View.GONE); + if (isChecked) { + mHistoryEmpty.setVisibility(View.VISIBLE); + mHistoryOff.setVisibility(View.GONE); + } else { + mHistoryOff.setVisibility(View.VISIBLE); + mHistoryEmpty.setVisibility(View.GONE); + } mTodayView.removeAllViews(); - mHistoryOff.setVisibility(View.VISIBLE); }; private final NotificationListenerService mListener = new NotificationListenerService() { @@ -303,6 +287,8 @@ public class NotificationHistoryActivity extends Activity { ((NotificationSbnAdapter) mDismissedRv.getAdapter()).onRebuildComplete( new ArrayList<>(Arrays.asList(dismissed))); } + + mCountdownLatch.countDown(); } @Override diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java index 5beacdd595c..f55d65c165b 100644 --- a/src/com/android/settings/password/ChooseLockGeneric.java +++ b/src/com/android/settings/password/ChooseLockGeneric.java @@ -143,7 +143,7 @@ public class ChooseLockGeneric extends SettingsActivity { static final int SKIP_FINGERPRINT_REQUEST = 104; private ChooseLockSettingsHelper mChooseLockSettingsHelper; - private DevicePolicyManager mDPM; + private DevicePolicyManager mDpm; private boolean mHasChallenge = false; private long mChallenge; private boolean mPasswordConfirmed = false; @@ -158,6 +158,8 @@ public class ChooseLockGeneric extends SettingsActivity { private boolean mIsSetNewPassword = false; private UserManager mUserManager; private ChooseLockGenericController mController; + private int mUnificationProfileId = UserHandle.USER_NULL; + private LockscreenCredential mUnificationProfileCredential; /** * From intent extra {@link ChooseLockSettingsHelper#EXTRA_KEY_REQUESTED_MIN_COMPLEXITY}. @@ -185,48 +187,57 @@ public class ChooseLockGeneric extends SettingsActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final Activity activity = getActivity(); + final Bundle arguments = getArguments(); if (!WizardManagerHelper.isDeviceProvisioned(activity) && !canRunBeforeDeviceProvisioned()) { Log.i(TAG, "Refusing to start because device is not provisioned"); activity.finish(); return; } - - String chooseLockAction = getActivity().getIntent().getAction(); - mFingerprintManager = Utils.getFingerprintManagerOrNull(getActivity()); - mFaceManager = Utils.getFaceManagerOrNull(getActivity()); - mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); - mChooseLockSettingsHelper = new ChooseLockSettingsHelper(this.getActivity()); - mLockPatternUtils = new LockPatternUtils(getActivity()); + final Intent intent = activity.getIntent(); + String chooseLockAction = intent.getAction(); + mFingerprintManager = Utils.getFingerprintManagerOrNull(activity); + mFaceManager = Utils.getFaceManagerOrNull(activity); + mDpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE); + mChooseLockSettingsHelper = new ChooseLockSettingsHelper(activity); + mLockPatternUtils = new LockPatternUtils(activity); mIsSetNewPassword = ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction) || ACTION_SET_NEW_PASSWORD.equals(chooseLockAction); // Defaults to needing to confirm credentials - final boolean confirmCredentials = getActivity().getIntent() + final boolean confirmCredentials = intent .getBooleanExtra(CONFIRM_CREDENTIALS, true); - if (getActivity() instanceof ChooseLockGeneric.InternalActivity) { + if (activity instanceof ChooseLockGeneric.InternalActivity) { mPasswordConfirmed = !confirmCredentials; - mUserPassword = getActivity().getIntent().getParcelableExtra( + mUserPassword = intent.getParcelableExtra( ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); } - mHasChallenge = getActivity().getIntent().getBooleanExtra( + mHasChallenge = intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false); - mChallenge = getActivity().getIntent().getLongExtra( + mChallenge = intent.getLongExtra( ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0); - mForFingerprint = getActivity().getIntent().getBooleanExtra( + mForFingerprint = intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false); - mForFace = getActivity().getIntent().getBooleanExtra( + mForFace = intent.getBooleanExtra( ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE, false); - mRequestedMinComplexity = getActivity().getIntent() + mRequestedMinComplexity = intent .getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_NONE); mCallerAppName = - getActivity().getIntent().getStringExtra(EXTRA_KEY_CALLER_APP_NAME); - mIsCallingAppAdmin = getActivity().getIntent() + intent.getStringExtra(EXTRA_KEY_CALLER_APP_NAME); + mIsCallingAppAdmin = intent .getBooleanExtra(EXTRA_KEY_IS_CALLING_APP_ADMIN, /* defValue= */ false); - mForChangeCredRequiredForBoot = getArguments() != null && getArguments().getBoolean( + mForChangeCredRequiredForBoot = arguments != null && arguments.getBoolean( ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT); - mUserManager = UserManager.get(getActivity()); + mUserManager = UserManager.get(activity); + + if (arguments != null) { + mUnificationProfileCredential = (LockscreenCredential) arguments.getParcelable( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL); + mUnificationProfileId = arguments.getInt( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, + UserHandle.USER_NULL); + } if (savedInstanceState != null) { mPasswordConfirmed = savedInstanceState.getBoolean(PASSWORD_CONFIRMED); @@ -242,19 +253,19 @@ public class ChooseLockGeneric extends SettingsActivity { // from Settings app itself. // c) Otherwise, use UserHandle.myUserId(). mUserId = Utils.getSecureTargetUser( - getActivity().getActivityToken(), - UserManager.get(getActivity()), - getArguments(), - getActivity().getIntent().getExtras()).getIdentifier(); + activity.getActivityToken(), + UserManager.get(activity), + arguments, + intent.getExtras()).getIdentifier(); mController = new ChooseLockGenericController( getContext(), mUserId, mRequestedMinComplexity, mLockPatternUtils); if (ACTION_SET_NEW_PASSWORD.equals(chooseLockAction) - && UserManager.get(getActivity()).isManagedProfile(mUserId) + && UserManager.get(activity).isManagedProfile(mUserId) && mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId)) { - getActivity().setTitle(R.string.lock_settings_picker_title_profile); + activity.setTitle(R.string.lock_settings_picker_title_profile); } - mManagedPasswordProvider = ManagedLockPasswordProvider.get(getActivity(), mUserId); + mManagedPasswordProvider = ManagedLockPasswordProvider.get(activity, mUserId); if (mPasswordConfirmed) { updatePreferencesOrFinish(savedInstanceState != null); @@ -264,9 +275,9 @@ public class ChooseLockGeneric extends SettingsActivity { } } else if (!mWaitingForConfirmation) { ChooseLockSettingsHelper helper = - new ChooseLockSettingsHelper(this.getActivity(), this); + new ChooseLockSettingsHelper(activity, this); boolean managedProfileWithUnifiedLock = - UserManager.get(getActivity()).isManagedProfile(mUserId) + UserManager.get(activity).isManagedProfile(mUserId) && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId); boolean skipConfirmation = managedProfileWithUnifiedLock && !mIsSetNewPassword; if (skipConfirmation @@ -632,9 +643,22 @@ public class ChooseLockGeneric extends SettingsActivity { boolean hideDisabled) { final PreferenceScreen entries = getPreferenceScreen(); - int adminEnforcedQuality = mDPM.getPasswordQuality(null, mUserId); + int adminEnforcedQuality = mDpm.getPasswordQuality(null, mUserId); EnforcedAdmin enforcedAdmin = RestrictedLockUtilsInternal.checkIfPasswordQualityIsSet( getActivity(), mUserId); + // If we are to unify a work challenge at the end of the credential enrollment, manually + // merge any password policy from that profile here, so we are enrolling a compliant + // password. This is because once unified, the profile's password policy will + // be enforced on the new credential. + if (mUnificationProfileId != UserHandle.USER_NULL) { + int profileEnforceQuality = mDpm.getPasswordQuality(null, mUnificationProfileId); + if (profileEnforceQuality > adminEnforcedQuality) { + adminEnforcedQuality = profileEnforceQuality; + enforcedAdmin = EnforcedAdmin.combine(enforcedAdmin, + RestrictedLockUtilsInternal.checkIfPasswordQualityIsSet( + getActivity(), mUnificationProfileId)); + } + } for (ScreenLockType lock : ScreenLockType.values()) { String key = lock.preferenceKey; @@ -704,6 +728,9 @@ public class ChooseLockGeneric extends SettingsActivity { if (mUserPassword != null) { builder.setPassword(mUserPassword); } + if (mUnificationProfileId != UserHandle.USER_NULL) { + builder.setProfileToUnify(mUnificationProfileId, mUnificationProfileCredential); + } return builder.build(); } @@ -719,6 +746,9 @@ public class ChooseLockGeneric extends SettingsActivity { if (mUserPassword != null) { builder.setPattern(mUserPassword); } + if (mUnificationProfileId != UserHandle.USER_NULL) { + builder.setProfileToUnify(mUnificationProfileId, mUnificationProfileCredential); + } return builder.build(); } diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java index ff94d8b8956..ebfc1afb436 100644 --- a/src/com/android/settings/password/ChooseLockPassword.java +++ b/src/com/android/settings/password/ChooseLockPassword.java @@ -32,6 +32,8 @@ import static com.android.internal.widget.PasswordValidationError.RECENTLY_USED; import static com.android.internal.widget.PasswordValidationError.TOO_LONG; import static com.android.internal.widget.PasswordValidationError.TOO_SHORT; import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY; +import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL; +import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID; import android.app.Activity; import android.app.admin.DevicePolicyManager; @@ -46,6 +48,7 @@ import android.graphics.Typeface; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.os.UserHandle; import android.text.Editable; import android.text.InputType; import android.text.Selection; @@ -153,6 +156,18 @@ public class ChooseLockPassword extends SettingsActivity { return this; } + /** + * Configures the launch such that at the end of the password enrollment, one of its + * managed profile (specified by {@code profileId}) will have its lockscreen unified + * to the parent user. The profile's current lockscreen credential needs to be specified by + * {@code credential}. + */ + public IntentBuilder setProfileToUnify(int profileId, LockscreenCredential credential) { + mIntent.putExtra(EXTRA_KEY_UNIFICATION_PROFILE_ID, profileId); + mIntent.putExtra(EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL, credential); + return this; + } + public Intent build() { return mIntent; } @@ -208,6 +223,7 @@ public class ChooseLockPassword extends SettingsActivity { @PasswordComplexity private int mMinComplexity = PASSWORD_COMPLEXITY_NONE; protected int mUserId; private byte[] mPasswordHistoryHashFactor; + private int mUnificationProfileId = UserHandle.USER_NULL; private LockPatternUtils mLockPatternUtils; private SaveAndFinishWorker mSaveAndFinishWorker; @@ -367,8 +383,19 @@ public class ChooseLockPassword extends SettingsActivity { mRequestedQuality = intent.getIntExtra( LockPatternUtils.PASSWORD_TYPE_KEY, PASSWORD_QUALITY_NUMERIC); + mUnificationProfileId = intent.getIntExtra( + EXTRA_KEY_UNIFICATION_PROFILE_ID, UserHandle.USER_NULL); mMinMetrics = mLockPatternUtils.getRequestedPasswordMetrics(mUserId); + // If we are to unify a work challenge at the end of the credential enrollment, manually + // merge any password policy from that profile here, so we are enrolling a compliant + // password. This is because once unified, the profile's password policy will + // be enforced on the new credential. + if (mUnificationProfileId != UserHandle.USER_NULL) { + mMinMetrics.maxWith( + mLockPatternUtils.getRequestedPasswordMetrics(mUnificationProfileId)); + } + mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity()); if (intent.getBooleanExtra( @@ -833,8 +860,16 @@ public class ChooseLockPassword extends SettingsActivity { FRAGMENT_TAG_SAVE_AND_FINISH).commit(); getFragmentManager().executePendingTransactions(); - final boolean required = getActivity().getIntent().getBooleanExtra( + final Intent intent = getActivity().getIntent(); + final boolean required = intent.getBooleanExtra( EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true); + if (mUnificationProfileId != UserHandle.USER_NULL) { + try (LockscreenCredential profileCredential = (LockscreenCredential) + intent.getParcelableExtra(EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)) { + mSaveAndFinishWorker.setProfileToUnify(mUnificationProfileId, + profileCredential); + } + } mSaveAndFinishWorker.start(mLockPatternUtils, required, mHasChallenge, mChallenge, mChosenPassword, mCurrentCredential, mUserId); } @@ -912,6 +947,9 @@ public class ChooseLockPassword extends SettingsActivity { protected Pair saveAndVerifyInBackground() { final boolean success = mUtils.setLockCredential( mChosenPassword, mCurrentCredential, mUserId); + if (success) { + unifyProfileCredentialIfRequested(); + } Intent result = null; if (success && mHasChallenge) { byte[] token; diff --git a/src/com/android/settings/password/ChooseLockPattern.java b/src/com/android/settings/password/ChooseLockPattern.java index b5670cacc43..ece3da8f247 100644 --- a/src/com/android/settings/password/ChooseLockPattern.java +++ b/src/com/android/settings/password/ChooseLockPattern.java @@ -16,6 +16,9 @@ package com.android.settings.password; +import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL; +import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID; + import android.app.Activity; import android.app.settings.SettingsEnums; import android.content.Context; @@ -23,6 +26,7 @@ import android.content.Intent; import android.content.res.ColorStateList; import android.content.res.Resources.Theme; import android.os.Bundle; +import android.os.UserHandle; import android.util.Log; import android.util.Pair; import android.util.TypedValue; @@ -50,6 +54,7 @@ import com.android.settings.SetupWizardUtils; import com.android.settings.Utils; import com.android.settings.core.InstrumentedFragment; import com.android.settings.notification.RedactionInterstitial; +import com.android.settings.password.ChooseLockPassword.IntentBuilder; import com.google.android.collect.Lists; import com.google.android.setupcompat.template.FooterBarMixin; @@ -130,6 +135,19 @@ public class ChooseLockPattern extends SettingsActivity { return this; } + /** + * Configures the launch such that at the end of the pattern enrollment, one of its + * managed profile (specified by {@code profileId}) will have its lockscreen unified + * to the parent user. The profile's current lockscreen credential needs to be specified by + * {@code credential}. + */ + public IntentBuilder setProfileToUnify(int profileId, LockscreenCredential credential) { + mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, profileId); + mIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL, + credential); + return this; + } + public Intent build() { return mIntent; } @@ -810,8 +828,18 @@ public class ChooseLockPattern extends SettingsActivity { FRAGMENT_TAG_SAVE_AND_FINISH).commit(); getFragmentManager().executePendingTransactions(); - final boolean required = getActivity().getIntent().getBooleanExtra( + final Intent intent = getActivity().getIntent(); + final boolean required = intent.getBooleanExtra( EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true); + if (intent.hasExtra(EXTRA_KEY_UNIFICATION_PROFILE_ID)) { + try (LockscreenCredential profileCredential = (LockscreenCredential) + intent.getParcelableExtra(EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)) { + mSaveAndFinishWorker.setProfileToUnify( + intent.getIntExtra(EXTRA_KEY_UNIFICATION_PROFILE_ID, + UserHandle.USER_NULL), + profileCredential); + } + } mSaveAndFinishWorker.start(mChooseLockSettingsHelper.utils(), required, mHasChallenge, mChallenge, mChosenPattern, mCurrentCredential, mUserId); } @@ -863,6 +891,9 @@ public class ChooseLockPattern extends SettingsActivity { final int userId = mUserId; final boolean success = mUtils.setLockCredential(mChosenPattern, mCurrentCredential, userId); + if (success) { + unifyProfileCredentialIfRequested(); + } Intent result = null; if (success && mHasChallenge) { byte[] token; diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java index 3353d62053f..3989ee66f02 100644 --- a/src/com/android/settings/password/ChooseLockSettingsHelper.java +++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java @@ -33,6 +33,7 @@ import androidx.fragment.app.Fragment; import com.android.internal.widget.LockPatternUtils; import com.android.settings.SetupWizardUtils; import com.android.settings.Utils; +import com.android.settings.core.SubSettingLauncher; import com.google.android.setupcompat.util.WizardManagerHelper; @@ -49,6 +50,17 @@ public final class ChooseLockSettingsHelper { public static final String EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT = "for_cred_req_boot"; public static final String EXTRA_KEY_FOREGROUND_ONLY = "foreground_only"; + /** + * When EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL and EXTRA_KEY_UNIFICATION_PROFILE_ID are + * provided to ChooseLockGeneric as fragment arguments {@link SubSettingLauncher#setArguments}, + * at the end of the password change flow, the supplied profile user + * (EXTRA_KEY_UNIFICATION_PROFILE_ID) will be unified to its parent. The current profile + * password is supplied by EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL. + */ + public static final String EXTRA_KEY_UNIFICATION_PROFILE_ID = "unification_profile_id"; + public static final String EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL = + "unification_profile_credential"; + /** * Intent extra for passing the requested min password complexity to later steps in the set new * screen lock flow. diff --git a/src/com/android/settings/password/SaveChosenLockWorkerBase.java b/src/com/android/settings/password/SaveChosenLockWorkerBase.java index 2798b3d7f47..26e4d5aa8ad 100644 --- a/src/com/android/settings/password/SaveChosenLockWorkerBase.java +++ b/src/com/android/settings/password/SaveChosenLockWorkerBase.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; +import android.os.UserHandle; import android.os.UserManager; import android.util.Pair; import android.widget.Toast; @@ -27,6 +28,7 @@ import android.widget.Toast; import androidx.fragment.app.Fragment; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockscreenCredential; import com.android.settings.R; /** @@ -44,6 +46,8 @@ abstract class SaveChosenLockWorkerBase extends Fragment { protected long mChallenge; protected boolean mWasSecureBefore; protected int mUserId; + protected int mUnificationProfileId = UserHandle.USER_NULL; + protected LockscreenCredential mUnificationProfileCredential; private boolean mBlocking; @@ -106,12 +110,27 @@ abstract class SaveChosenLockWorkerBase extends Fragment { if (mListener != null) { mListener.onChosenLockSaveFinished(mWasSecureBefore, mResultData); } + if (mUnificationProfileCredential != null) { + mUnificationProfileCredential.zeroize(); + } } public void setBlocking(boolean blocking) { mBlocking = blocking; } + public void setProfileToUnify(int profileId, LockscreenCredential credential) { + mUnificationProfileId = profileId; + mUnificationProfileCredential = credential.duplicate(); + } + + protected void unifyProfileCredentialIfRequested() { + if (mUnificationProfileId != UserHandle.USER_NULL) { + mUtils.setSeparateProfileChallengeEnabled(mUnificationProfileId, false, + mUnificationProfileCredential); + } + } + private class Task extends AsyncTask> { @Override diff --git a/src/com/android/settings/search/CustomSiteMapRegistry.java b/src/com/android/settings/search/CustomSiteMapRegistry.java index 756479b2495..afda72b2d68 100644 --- a/src/com/android/settings/search/CustomSiteMapRegistry.java +++ b/src/com/android/settings/search/CustomSiteMapRegistry.java @@ -27,6 +27,8 @@ import com.android.settings.fuelgauge.PowerUsageSummary; import com.android.settings.location.LocationSettings; import com.android.settings.location.RecentLocationRequestSeeAllFragment; import com.android.settings.network.NetworkDashboardFragment; +import com.android.settings.notification.zen.ZenModeBlockedEffectsSettings; +import com.android.settings.notification.zen.ZenModeRestrictNotificationsSettings; import com.android.settings.security.SecuritySettings; import com.android.settings.security.screenlock.ScreenLockSettings; import com.android.settings.system.SystemDashboardFragment; @@ -59,5 +61,7 @@ public class CustomSiteMapRegistry { ConnectedDeviceDashboardFragment.class.getName()); CUSTOM_SITE_MAP.put(UserBackupSettingsActivity.class.getName(), SystemDashboardFragment.class.getName()); + CUSTOM_SITE_MAP.put(ZenModeBlockedEffectsSettings.class.getName(), + ZenModeRestrictNotificationsSettings.class.getName()); } } diff --git a/src/com/android/settings/security/LockUnificationPreferenceController.java b/src/com/android/settings/security/LockUnificationPreferenceController.java index 4bac601cf26..9cacf8e2eca 100644 --- a/src/com/android/settings/security/LockUnificationPreferenceController.java +++ b/src/com/android/settings/security/LockUnificationPreferenceController.java @@ -16,7 +16,6 @@ package com.android.settings.security; -import static com.android.settings.security.SecuritySettings.UNIFY_LOCK_CONFIRM_DEVICE_REQUEST; import static com.android.settings.security.SecuritySettings.UNIFY_LOCK_CONFIRM_PROFILE_REQUEST; import static com.android.settings.security.SecuritySettings.UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST; @@ -48,12 +47,14 @@ import com.android.settingslib.core.AbstractPreferenceController; * Controller for password unification/un-unification flows. * * When password is being unified, there may be two cases: - * 1. If work password is not empty and satisfies device-wide policies (if any), it will be made - * into device-wide password. To do that we need both current device and profile passwords - * because both of them will be changed as a result. - * 2. Otherwise device-wide password is preserved. In this case we only need current profile - * password, but after unifying the passwords we proceed to ask the user for a new device - * password. + * 1. If device password will satisfy device-wide policies post-unification (when password policy + * set on the work challenge will be enforced on device password), the device password is + * preserved while work challenge is unified. Only the current work challenge is required + * in this flow. + * 2. Otherwise the user will need to enroll a new compliant device password before unification + * takes place. In this case we first confirm the current work challenge, then guide the user + * through an enrollment flow for the new device password, and finally unify the work challenge + * at the very end. */ public class LockUnificationPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener { @@ -73,7 +74,7 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr private LockscreenCredential mCurrentDevicePassword; private LockscreenCredential mCurrentProfilePassword; - private boolean mKeepDeviceLock; + private boolean mRequireNewDevicePassword; @Override public void displayPreference(PreferenceScreen screen) { @@ -112,13 +113,9 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr } final boolean useOneLock = (Boolean) value; if (useOneLock) { - // Keep current device (personal) lock if the profile lock is empty or is not compliant - // with the policy on personal side. - mKeepDeviceLock = - mLockPatternUtils.getKeyguardStoredPasswordQuality(mProfileUserId) - < DevicePolicyManager.PASSWORD_QUALITY_SOMETHING - || !mDpm.isProfileActivePasswordSufficientForParent(mProfileUserId); - UnificationConfirmationDialog.newInstance(!mKeepDeviceLock).show(mHost); + mRequireNewDevicePassword = !mDpm.isPasswordSufficientAfterProfileUnification( + UserHandle.myUserId(), mProfileUserId); + startUnification(); } else { final String title = mContext.getString(R.string.unlock_set_unlock_launch_picker_title); final ChooseLockSettingsHelper helper = @@ -149,13 +146,9 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr public boolean handleActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST && resultCode == Activity.RESULT_OK) { - ununifyLocks(); - return true; - } else if (requestCode == UNIFY_LOCK_CONFIRM_DEVICE_REQUEST - && resultCode == Activity.RESULT_OK) { mCurrentDevicePassword = data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD); - launchConfirmProfileLock(); + ununifyLocks(); return true; } else if (requestCode == UNIFY_LOCK_CONFIRM_PROFILE_REQUEST && resultCode == Activity.RESULT_OK) { @@ -170,67 +163,44 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr private void ununifyLocks() { final Bundle extras = new Bundle(); extras.putInt(Intent.EXTRA_USER_ID, mProfileUserId); + extras.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD, mCurrentDevicePassword); new SubSettingLauncher(mContext) .setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName()) - .setTitleRes(R.string.lock_settings_picker_title_profile) + .setTitleRes(R.string.lock_settings_picker_title_profile) .setSourceMetricsCategory(mHost.getMetricsCategory()) .setArguments(extras) .launch(); } - /** Asks the user to confirm device lock (if there is one) and proceeds to ask profile lock. */ - private void launchConfirmDeviceAndProfileLock() { - final String title = mContext.getString( - R.string.unlock_set_unlock_launch_picker_title); - final ChooseLockSettingsHelper helper = - new ChooseLockSettingsHelper(mHost.getActivity(), mHost); - if (!helper.launchConfirmationActivity( - UNIFY_LOCK_CONFIRM_DEVICE_REQUEST, title, true, MY_USER_ID)) { - launchConfirmProfileLock(); - } - } - - private void launchConfirmProfileLock() { + void startUnification() { + // Confirm profile lock final String title = mContext.getString( R.string.unlock_set_unlock_launch_picker_title_profile); final ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(mHost.getActivity(), mHost); if (!helper.launchConfirmationActivity( UNIFY_LOCK_CONFIRM_PROFILE_REQUEST, title, true, mProfileUserId)) { + // If profile has no lock, go straight to unification. unifyLocks(); // TODO: update relevant prefs. // createPreferenceHierarchy(); } } - void startUnification() { - // If the device lock stays the same, only confirm profile lock. Otherwise confirm both. - if (mKeepDeviceLock) { - launchConfirmProfileLock(); - } else { - launchConfirmDeviceAndProfileLock(); - } - } - private void unifyLocks() { - if (mKeepDeviceLock) { - unifyKeepingDeviceLock(); - promptForNewDeviceLock(); + if (mRequireNewDevicePassword) { + promptForNewDeviceLockAndThenUnify(); } else { - unifyKeepingWorkLock(); + unifyKeepingDeviceLock(); + } + if (mCurrentDevicePassword != null) { + mCurrentDevicePassword.zeroize(); + mCurrentDevicePassword = null; + } + if (mCurrentProfilePassword != null) { + mCurrentProfilePassword.zeroize(); + mCurrentProfilePassword = null; } - mCurrentDevicePassword = null; - mCurrentProfilePassword = null; - } - - private void unifyKeepingWorkLock() { - mLockPatternUtils.setLockCredential( - mCurrentProfilePassword, mCurrentDevicePassword, MY_USER_ID); - mLockPatternUtils.setSeparateProfileChallengeEnabled(mProfileUserId, false, - mCurrentProfilePassword); - final boolean profilePatternVisibility = - mLockPatternUtils.isVisiblePatternEnabled(mProfileUserId); - mLockPatternUtils.setVisiblePatternEnabled(profilePatternVisibility, MY_USER_ID); } private void unifyKeepingDeviceLock() { @@ -238,11 +208,16 @@ public class LockUnificationPreferenceController extends AbstractPreferenceContr mCurrentProfilePassword); } - private void promptForNewDeviceLock() { + private void promptForNewDeviceLockAndThenUnify() { + final Bundle extras = new Bundle(); + extras.putInt(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, mProfileUserId); + extras.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL, + mCurrentProfilePassword); new SubSettingLauncher(mContext) .setDestination(ChooseLockGeneric.ChooseLockGenericFragment.class.getName()) .setTitleRes(R.string.lock_settings_picker_title) .setSourceMetricsCategory(mHost.getMetricsCategory()) + .setArguments(extras) .launch(); } diff --git a/src/com/android/settings/security/SecuritySettings.java b/src/com/android/settings/security/SecuritySettings.java index effbd70dc82..c8288c6c7f2 100644 --- a/src/com/android/settings/security/SecuritySettings.java +++ b/src/com/android/settings/security/SecuritySettings.java @@ -47,7 +47,6 @@ public class SecuritySettings extends DashboardFragment { private static final String WORK_PROFILE_SECURITY_CATEGORY = "security_category_profile"; public static final int CHANGE_TRUST_AGENT_SETTINGS = 126; - public static final int UNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 128; public static final int UNIFY_LOCK_CONFIRM_PROFILE_REQUEST = 129; public static final int UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 130; diff --git a/src/com/android/settings/users/MultiUserSwitchBarController.java b/src/com/android/settings/users/MultiUserSwitchBarController.java index 58de14963fa..a5fdf9b3279 100644 --- a/src/com/android/settings/users/MultiUserSwitchBarController.java +++ b/src/com/android/settings/users/MultiUserSwitchBarController.java @@ -52,6 +52,8 @@ public class MultiUserSwitchBarController implements SwitchWidgetController.OnSw mListener = listener; mUserCapabilities = UserCapabilities.create(context); mSwitchBar.setChecked(mUserCapabilities.mUserSwitcherEnabled); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.USER_SWITCHER_ENABLED, mSwitchBar.isChecked() ? 1 : 0); if (mUserCapabilities.mDisallowSwitchUser) { mSwitchBar.setDisabledByAdmin(RestrictedLockUtilsInternal diff --git a/tests/robotests/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceControllerTest.java deleted file mode 100644 index 93167354206..00000000000 --- a/tests/robotests/src/com/android/settings/applications/AppOpenSupportedLinksPreferenceControllerTest.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright (C) 2020 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.applications; - -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; -import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; - -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.Mockito.doReturn; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.content.pm.PackageManager; -import android.util.ArraySet; - -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceManager; -import androidx.preference.PreferenceScreen; - -import com.android.settings.testutils.shadow.ShadowUtils; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -@RunWith(RobolectricTestRunner.class) -public class AppOpenSupportedLinksPreferenceControllerTest { - private static final String TEST_KEY = "test_key"; - private static final String TEST_DOMAIN_LINK = "aaa.bbb.ccc"; - private static final String TEST_PACKAGE = "ssl.test.package.com"; - - @Mock - private PackageManager mPackageManager; - - private Context mContext; - private PreferenceManager mPreferenceManager; - private PreferenceScreen mScreen; - private PreferenceCategory mCategory; - private AppOpenSupportedLinksPreferenceController mController; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = spy(RuntimeEnvironment.application); - doReturn(mPackageManager).when(mContext).getPackageManager(); - mPreferenceManager = new PreferenceManager(mContext); - mScreen = spy(mPreferenceManager.createPreferenceScreen(mContext)); - mCategory = spy(new PreferenceCategory(mContext)); - mController = spy(new AppOpenSupportedLinksPreferenceController(mContext, TEST_KEY)); - mController.setInit(TEST_PACKAGE); - } - - @Test - public void displayPreference_statusAlways_allowOpenChecked() { - init(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS); - - mController.displayPreference(mScreen); - - assertThat(mController.mAllowOpening.isChecked()).isTrue(); - assertThat(mController.mAskEveryTime.isChecked()).isFalse(); - assertThat(mController.mNotAllowed.isChecked()).isFalse(); - } - - @Test - public void displayPreference_statusAsk_askEveryTimeChecked() { - init(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK); - - mController.displayPreference(mScreen); - - assertThat(mController.mAllowOpening.isChecked()).isFalse(); - assertThat(mController.mAskEveryTime.isChecked()).isTrue(); - assertThat(mController.mNotAllowed.isChecked()).isFalse(); - } - - @Test - public void displayPreference_statusNever_notAllowedChecked() { - init(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER); - - mController.displayPreference(mScreen); - - assertThat(mController.mAllowOpening.isChecked()).isFalse(); - assertThat(mController.mAskEveryTime.isChecked()).isFalse(); - assertThat(mController.mNotAllowed.isChecked()).isTrue(); - } - - @Test - @Config(shadows = ShadowUtils.class) - public void getEntriesNo_oneHandledDomains_returnOne() { - initHandledDomains(); - - assertThat(mController.getEntriesNo()).isEqualTo(1); - } - - private void init(int status) { - doReturn(mCategory).when(mScreen).findPreference(any(CharSequence.class)); - doReturn(true).when(mCategory).addPreference(any(Preference.class)); - when(mPackageManager.getIntentVerificationStatusAsUser(anyString(), anyInt())).thenReturn( - status); - } - - private void initHandledDomains() { - final ArraySet domainLinks = new ArraySet<>(); - domainLinks.add(TEST_DOMAIN_LINK); - ShadowUtils.setHandledDomains(domainLinks); - } -} diff --git a/tests/robotests/src/com/android/settings/applications/OpenSupportedLinksTest.java b/tests/robotests/src/com/android/settings/applications/OpenSupportedLinksTest.java index f9d4ca83a41..ea2c4ecf50d 100644 --- a/tests/robotests/src/com/android/settings/applications/OpenSupportedLinksTest.java +++ b/tests/robotests/src/com/android/settings/applications/OpenSupportedLinksTest.java @@ -15,15 +15,27 @@ */ package com.android.settings.applications; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; + 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.Mockito.doReturn; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; import android.content.Context; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.util.ArraySet; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; + import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settingslib.widget.FooterPreference; @@ -31,6 +43,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @@ -40,15 +54,25 @@ import org.robolectric.annotation.Config; public class OpenSupportedLinksTest { private static final String TEST_FOOTER_TITLE = "FooterTitle"; private static final String TEST_DOMAIN_LINK = "aaa.bbb.ccc"; + private static final String TEST_SUMMARY = "TestSummary"; + private static final String TEST_PACKAGE = "ssl.test.package.com"; + + @Mock + private PackageManager mPackageManager; + @Mock + private Resources mResources; private Context mContext; private TestFragment mSettings; private FooterPreference mFooter; + private PreferenceCategory mCategory; @Before public void setUp() { + MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); - mSettings = spy(new TestFragment(mContext)); + mSettings = spy(new TestFragment(mContext, mPackageManager)); + mCategory = spy(new PreferenceCategory(mContext)); mFooter = new FooterPreference.Builder(mContext).setTitle(TEST_FOOTER_TITLE).build(); } @@ -75,18 +99,68 @@ public class OpenSupportedLinksTest { assertThat(mFooter.getTitle().toString()).contains(TEST_DOMAIN_LINK); } + @Test + public void initRadioPreferencesGroup_statusAlways_allowOpenChecked() { + init(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS); + + mSettings.initRadioPreferencesGroup(); + + assertThat(mSettings.mAllowOpening.isChecked()).isTrue(); + assertThat(mSettings.mAskEveryTime.isChecked()).isFalse(); + assertThat(mSettings.mNotAllowed.isChecked()).isFalse(); + } + + @Test + public void initRadioPreferencesGroup_statusAsk_askEveryTimeChecked() { + init(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK); + + mSettings.initRadioPreferencesGroup(); + + assertThat(mSettings.mAllowOpening.isChecked()).isFalse(); + assertThat(mSettings.mAskEveryTime.isChecked()).isTrue(); + assertThat(mSettings.mNotAllowed.isChecked()).isFalse(); + } + + @Test + public void initRadioPreferencesGroup_statusNever_notAllowedChecked() { + init(INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER); + + mSettings.initRadioPreferencesGroup(); + + assertThat(mSettings.mAllowOpening.isChecked()).isFalse(); + assertThat(mSettings.mAskEveryTime.isChecked()).isFalse(); + assertThat(mSettings.mNotAllowed.isChecked()).isTrue(); + } + + @Test + public void getEntriesNo_oneHandledDomains_returnOne() { + initHandledDomains(); + + assertThat(mSettings.getEntriesNo()).isEqualTo(1); + } + + private void init(int status) { + doReturn(status).when(mPackageManager).getIntentVerificationStatusAsUser(anyString(), + anyInt()); + doReturn(mCategory).when(mSettings).findPreference(any(CharSequence.class)); + doReturn(mResources).when(mSettings).getResources(); + when(mResources.getQuantityString(anyInt(), anyInt(), anyInt())).thenReturn(TEST_SUMMARY); + doReturn(true).when(mCategory).addPreference(any(Preference.class)); + } + public static class TestFragment extends OpenSupportedLinks { private final Context mContext; - public TestFragment(Context context) { + public TestFragment(Context context, PackageManager packageManager) { mContext = context; - mPackageInfo = new PackageInfo(); - mPackageInfo.packageName = "ssl.test.package.com"; - } - - @Override - protected PackageManager getPackageManager() { - return mContext.getPackageManager(); + mPackageManager = packageManager; + mPackageName = TEST_PACKAGE; } } + + private void initHandledDomains() { + final ArraySet domainLinks = new ArraySet<>(); + domainLinks.add(TEST_DOMAIN_LINK); + ShadowUtils.setHandledDomains(domainLinks); + } } diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java index 8340243cf49..b535bc142d3 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java @@ -35,12 +35,14 @@ import static org.robolectric.Shadows.shadowOf; import android.app.Activity; import android.app.admin.DevicePolicyManager; import android.content.Intent; +import android.os.Bundle; import android.provider.Settings.Global; import androidx.annotation.Nullable; import androidx.preference.Preference; import com.android.internal.widget.LockPatternUtils; +import com.android.internal.widget.LockscreenCredential; import com.android.settings.R; import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment; @@ -312,6 +314,56 @@ public class ChooseLockGenericTest { .isEqualTo("app name"); } + @Test + public void testUnifyProfile_IntentPassedToChooseLockPassword() { + final Bundle arguments = new Bundle(); + arguments.putInt(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, 11); + arguments.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL, + LockscreenCredential.createNone()); + mFragment.setArguments(arguments); + + Intent intent = new Intent().putExtra( + LockPatternUtils.PASSWORD_TYPE_KEY, + DevicePolicyManager.PASSWORD_QUALITY_NUMERIC); + initActivity(intent); + + mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */); + + Intent nextIntent = shadowOf(mActivity).getNextStartedActivity(); + assertThat(nextIntent).isNotNull(); + assertThat(nextIntent.getComponent().getClassName()).isEqualTo( + ChooseLockPassword.class.getName()); + assertThat(nextIntent.getIntExtra( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, 0)).isEqualTo(11); + assertThat((LockscreenCredential) nextIntent.getParcelableExtra( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)).isNotNull(); + } + + @Test + public void testUnifyProfile_IntentPassedToChooseLockPattern() { + final Bundle arguments = new Bundle(); + arguments.putInt(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, 13); + arguments.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL, + LockscreenCredential.createNone()); + mFragment.setArguments(arguments); + + Intent intent = new Intent().putExtra( + LockPatternUtils.PASSWORD_TYPE_KEY, + DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); + initActivity(intent); + + mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */); + + Intent nextIntent = shadowOf(mActivity).getNextStartedActivity(); + assertThat(nextIntent).isNotNull(); + assertThat(nextIntent.getComponent().getClassName()).isEqualTo( + ChooseLockPattern.class.getName()); + assertThat(nextIntent.getIntExtra( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, 0)).isEqualTo(13); + assertThat((LockscreenCredential) nextIntent.getParcelableExtra( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)).isNotNull(); + } + private void initActivity(@Nullable Intent intent) { if (intent == null) { intent = new Intent(); diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java index 4bbf51d981f..5ec6f41abbf 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java @@ -147,6 +147,21 @@ public class ChooseLockPasswordTest { assertThat(intent.hasExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY)).isFalse(); } + @Test + public void intentBuilder_setProfileToUnify_shouldAddExtras() { + Intent intent = new IntentBuilder(application) + .setProfileToUnify(23, LockscreenCredential.createNone()) + .build(); + + assertThat(intent.getIntExtra(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, 0)) + .named("EXTRA_KEY_UNIFICATION_PROFILE_ID") + .isEqualTo(23); + assertThat((LockscreenCredential) intent.getParcelableExtra( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)) + .named("EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL") + .isNotNull(); + } + @Test public void processAndValidatePasswordRequirements_noMinPasswordComplexity() { mShadowDpm.setPasswordQuality(PASSWORD_QUALITY_ALPHABETIC); diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java index 01007449fd6..557e7c169c6 100644 --- a/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java +++ b/tests/robotests/src/com/android/settings/password/ChooseLockPatternTest.java @@ -92,6 +92,21 @@ public class ChooseLockPatternTest { .isEqualTo(123); } + @Test + public void intentBuilder_setProfileToUnify_shouldAddExtras() { + Intent intent = new IntentBuilder(application) + .setProfileToUnify(23, LockscreenCredential.createNone()) + .build(); + + assertThat(intent.getIntExtra(ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID, 0)) + .named("EXTRA_KEY_UNIFICATION_PROFILE_ID") + .isEqualTo(23); + assertThat((LockscreenCredential) intent.getParcelableExtra( + ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)) + .named("EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL") + .isNotNull(); + } + @Config(qualifiers = "sw400dp") @Test public void fingerprintExtraSet_shouldDisplayFingerprintIcon() { diff --git a/tests/robotests/src/com/android/settings/search/CustomSiteMapRegistryTest.java b/tests/robotests/src/com/android/settings/search/CustomSiteMapRegistryTest.java index 5c78a6bde68..a3e88d96ca3 100644 --- a/tests/robotests/src/com/android/settings/search/CustomSiteMapRegistryTest.java +++ b/tests/robotests/src/com/android/settings/search/CustomSiteMapRegistryTest.java @@ -27,6 +27,8 @@ import com.android.settings.fuelgauge.PowerUsageSummary; import com.android.settings.location.LocationSettings; import com.android.settings.location.RecentLocationRequestSeeAllFragment; import com.android.settings.network.NetworkDashboardFragment; +import com.android.settings.notification.zen.ZenModeBlockedEffectsSettings; +import com.android.settings.notification.zen.ZenModeRestrictNotificationsSettings; import com.android.settings.security.SecuritySettings; import com.android.settings.security.screenlock.ScreenLockSettings; import com.android.settings.system.SystemDashboardFragment; @@ -85,4 +87,11 @@ public class CustomSiteMapRegistryTest { UserBackupSettingsActivity.class.getName())).isEqualTo( SystemDashboardFragment.class.getName()); } + + @Test + public void shouldContainZenModeBlockedEffectsSettingsPairs() { + assertThat(CustomSiteMapRegistry.CUSTOM_SITE_MAP.get( + ZenModeBlockedEffectsSettings.class.getName())).isEqualTo( + ZenModeRestrictNotificationsSettings.class.getName()); + } }