diff --git a/color-check-baseline.xml b/color-check-baseline.xml index 41cb12d03b5..3cb964fefd8 100644 --- a/color-check-baseline.xml +++ b/color-check-baseline.xml @@ -3037,4 +3037,36 @@ column="5"/> + + + + + + + + diff --git a/res/drawable-nodpi/color_mode_preview.jpg b/res/drawable-nodpi/color_mode_preview.jpg index 51dedbf48ad..804bcf1961a 100644 Binary files a/res/drawable-nodpi/color_mode_preview.jpg and b/res/drawable-nodpi/color_mode_preview.jpg differ diff --git a/res/drawable/face_enroll_introduction.xml b/res/drawable/face_enroll_introduction.xml index 6065f237237..217b13c2ff2 100644 --- a/res/drawable/face_enroll_introduction.xml +++ b/res/drawable/face_enroll_introduction.xml @@ -16,13 +16,13 @@ --> diff --git a/res/drawable/ic_content_copy_grey600_24dp.xml b/res/drawable/ic_content_copy_grey600_24dp.xml index 827c66ebab0..ba17ab658e3 100644 --- a/res/drawable/ic_content_copy_grey600_24dp.xml +++ b/res/drawable/ic_content_copy_grey600_24dp.xml @@ -1,9 +1,10 @@ + android:fillColor="@android:color/white"/> diff --git a/res/drawable/ic_devices_other_opaque_black.xml b/res/drawable/ic_devices_other_opaque_black.xml index 1b5af2d97dc..40cf527ae69 100644 --- a/res/drawable/ic_devices_other_opaque_black.xml +++ b/res/drawable/ic_devices_other_opaque_black.xml @@ -16,9 +16,10 @@ diff --git a/res/drawable/ic_face_24dp.xml b/res/drawable/ic_face_24dp.xml new file mode 100644 index 00000000000..7920c12570e --- /dev/null +++ b/res/drawable/ic_face_24dp.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/res/drawable/ic_friction_lock_closed.xml b/res/drawable/ic_friction_lock_closed.xml index 2f035e77baa..2c34060ccd6 100644 --- a/res/drawable/ic_friction_lock_closed.xml +++ b/res/drawable/ic_friction_lock_closed.xml @@ -17,9 +17,10 @@ diff --git a/res/drawable/ic_settings_adaptive_sleep.xml b/res/drawable/ic_settings_adaptive_sleep.xml new file mode 100644 index 00000000000..ac103dd4431 --- /dev/null +++ b/res/drawable/ic_settings_adaptive_sleep.xml @@ -0,0 +1,31 @@ + + + + + + + \ No newline at end of file diff --git a/res/drawable/ic_settings_disable.xml b/res/drawable/ic_settings_disable.xml index d0edf4a4bd3..e7a8f4116cb 100644 --- a/res/drawable/ic_settings_disable.xml +++ b/res/drawable/ic_settings_disable.xml @@ -18,8 +18,9 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24" - android:viewportHeight="24"> - + android:viewportHeight="24" + android:tint="?android:attr/colorControlNormal"> + diff --git a/res/drawable/ic_settings_enable.xml b/res/drawable/ic_settings_enable.xml index 560daef774a..673471d874e 100644 --- a/res/drawable/ic_settings_enable.xml +++ b/res/drawable/ic_settings_enable.xml @@ -18,8 +18,9 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24" - android:viewportHeight="24"> + android:viewportHeight="24" + android:tint="?android:attr/colorControlNormal"> diff --git a/res/drawable/ic_settings_gestures.xml b/res/drawable/ic_settings_gestures.xml index c75e7c3b2e1..f1c1625022a 100644 --- a/res/drawable/ic_settings_gestures.xml +++ b/res/drawable/ic_settings_gestures.xml @@ -16,10 +16,13 @@ + android:pathData="M17,18L7,18L7,6L17,6L17,7L19,7L19,3C19,1.895 18.105,1 17,1L7,1C5.895,1 5,1.895 5,3L5,21C5,22.105 5.895,23 7,23L17,23C18.105,23 19,22.105 19,21L19,17L17,17L17,18ZM7,3L17,3L17,4L7,4L7,3ZM17,21L7,21L7,20L17,20L17,21ZM17.94,12.06L20,13L17.94,13.94L17,16L16.06,13.94L14,13L16.06,12.06L17,10L17.94,12.06ZM20.63,8.38L22,9L20.63,9.63L20,11L19.38,9.63L18,9L19.38,8.38L20,7L20.63,8.38Z" + android:strokeColor="#00000000" + android:fillType="nonZero" + android:fillColor="#000000" + android:strokeWidth="1"/> \ No newline at end of file diff --git a/res/drawable/ic_sync_problem_24dp.xml b/res/drawable/ic_sync_problem_24dp.xml index 2139e98ec90..200a1b0ebbf 100644 --- a/res/drawable/ic_sync_problem_24dp.xml +++ b/res/drawable/ic_sync_problem_24dp.xml @@ -21,6 +21,6 @@ android:viewportHeight="24.0" android:tint="?android:attr/colorControlNormal"> + android:fillColor="@android:color/white" + android:pathData="M11 4.07v2.02C8.17 6.57 6 9.03 6 12c0 2.22 1.21 4.15 3 5.19V14h2v6H5v-2h1.74C5.07 16.54 4 14.4 4 12c0-4.08 3.05-7.44 7-7.93zm8.51 10.67c0.3 0.52 0.49 1.11 0.49 1.76 0 1.93-1.57 3.5-3.5 3.5-0.65 0-1.25-0.19-1.77-0.49-0.65-0.38-1.17-0.96-1.46-1.67-0.17-0.41-0.27-0.87-0.27-1.34 0-1.93 1.57-3.5 3.5-3.5 0.48 0 0.93 0.1 1.35 0.27 0.09-0.41 0.15 -0.83 0.15 -1.27 0-2.22-1.21-4.15-3-5.19V10h-2V4h6v2h-1.74C18.93 7.46 20 9.6 20 12c0 0.96-0.18 1.89-0.49 2.74zM17 18h-1v1h1v-1zm0-4h-1v3h1v-3z" /> diff --git a/res/layout/contextual_slice_deferred_setup.xml b/res/layout/contextual_slice_deferred_setup.xml index e695d1ddb12..7d5b688c1e8 100644 --- a/res/layout/contextual_slice_deferred_setup.xml +++ b/res/layout/contextual_slice_deferred_setup.xml @@ -25,7 +25,7 @@ android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" - android:gravity="left" + android:gravity="start" android:orientation="vertical" android:paddingEnd="@dimen/contextual_card_padding_end" android:paddingTop="@dimen/contextual_deferred_setup_card_padding_top" diff --git a/res/layout/face_enroll_introduction.xml b/res/layout/face_enroll_introduction.xml index 00ab4433c8b..f551e3637a6 100644 --- a/res/layout/face_enroll_introduction.xml +++ b/res/layout/face_enroll_introduction.xml @@ -56,7 +56,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" style="@style/SudContentIllustration" - app:sudVideo="@raw/face_enroll_introduction_animation"/> + app:sudVideo="@raw/face_settings"/> @@ -65,13 +65,35 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - android:layout_gravity="center_horizontal|bottom"> + android:layout_gravity="center_horizontal|bottom" + android:paddingTop="12dp"> + + + + + + + + + @*android:color/material_grey_800 #AECBFA #5F6368 + ?android:attr/colorAccent diff --git a/res/values/colors.xml b/res/values/colors.xml index 4a4c896a770..7114bb15152 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -147,4 +147,5 @@ @*android:color/background_device_default_light + #ffdadce0 \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 856bd210864..9e01877debd 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -790,13 +790,13 @@ - Automatically lock + Lock after screen timeout - %1$s after sleep + %1$s after timeout - Immediately after sleep, except when kept unlocked by %1$s + Immediately after timeout, except when kept unlocked by %1$s - %1$s after sleep, except when kept unlocked by %2$s + %1$s after timeout, except when kept unlocked by %2$s Show owner info on lock screen @@ -808,7 +808,7 @@ Show lockdown option - Display power button option that turns off Smart Lock, fingerprint unlocking, and notifications on the lock screen + Display power button option that turns off Smart Lock, biometric unlocking, and notifications on the lock screen Trust agents only extend unlock @@ -882,17 +882,19 @@ Screen lock - + Face added - - Tap to set up face authentication + + Set up face unlock - Face authentication + Face unlock + + Face unlock for work - How to set up Face unlock + How to set up face unlock - Set up Face unlock - + Set up face unlock + Use your face to authenticate @@ -910,7 +912,7 @@ Cancel Unlock with your face - + Use your face to authenticate Use your face to unlock your phone, authorize purchases, or sign in to apps. @@ -919,6 +921,8 @@ Use your face to unlock your phone, authorize purchases, or sign in to apps + + @@ -950,29 +954,30 @@ Use face unlock for Unlocking your phone - + App sign-in \u0026 payments - Require for face unlock - - Open eyes looking at screen - - To unlock the phone, always require looking at the screen with your eyes open + Requirements for face unlock + + Require eyes to be open + + To unlock the phone, your eyes must be open - Confirm button + Always require confirmation - When authenticating for apps, always require confirmation + When using face unlock in apps, always require confirmation step Delete face data - Set up new face unlock + Set up face unlock - Use Face unlock to unlock your device, sign in to apps, and confirm payments.\n\nKeep in mind:\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face while your eyes are open.\n\nYour phone can be unlocked by someone who looks a lot like you, say, your child or an identical sibling. + Use face unlock to unlock your device, sign in to apps, and confirm payments.\n\nKeep in mind:\nLooking at the phone can unlock it when you don\u2019t intend to.\n\nYour phone can be unlocked by someone else if it\u2019s held up to your face, even if your eyes are closed.\n\nYour phone can be unlocked by someone who looks a lot like you, say, an identical sibling. Delete face data? - Data recorded by face unlock will be permanently and securely deleted. After removal, you will need your PIN, pattern, or password to unlock your phone, sign in to apps, and confirm payments. - + The images and biometric data used by face unlock will be permanently and securely deleted. After removal, you will need your PIN, pattern, or password to unlock your phone, sign in to apps, and confirm payments. + + Use face unlock to unlock your phone @@ -1072,12 +1077,12 @@ Protect your device with a screen lock option so no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up fingerprint. Tap Cancel, then set a PIN, pattern, or password. Protect your phone with a screen lock option so no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up fingerprint. Tap Cancel, then set a PIN, pattern, or password. - - Protect your tablet with a screen lock option so no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up face authentication. Tap Cancel, then set a PIN, pattern, or password. - - Protect your device with a screen lock option so no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up face authentication. Tap Cancel, then set a PIN, pattern, or password. - - Protect your phone with a screen lock option so no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up face authentication. Tap Cancel, then set a PIN, pattern, or password. + + By protecting your tablet with a screen lock option, no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up face unlock. To go back, tap Cancel. + + By protecting your device with a screen lock option, no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up face unlock. To go back, tap Cancel. + + By protecting your phone with a screen lock option, no one will be able to use it if it is lost or stolen. You also need a screen lock option to set up face unlock. To go back, tap Cancel. Skip PIN setup? @@ -1321,7 +1326,7 @@ Choose your backup screen lock method - + Choose your backup screen lock method @@ -1399,19 +1404,19 @@ You can unlock your phone using your fingerprint. For security, this option requires a backup screen lock. - - Face authentication + Pattern + + Face unlock + Pattern - - Face authentication + PIN + + Face unlock + PIN - - Face authentication + Password + + Face unlock + Password - - Continue without face authentication + + Continue without face unlock - + You can unlock your phone using your face. For security, this option requires a backup screen lock. @@ -2826,17 +2831,24 @@ Display white balance + + Screen attention - On / Screen won’t turn off if you’re looking at it + On / Screen won\u2019t turn off if you\u2019re looking at it Off + + Camera access needed + + Tap to manage permissions for Device Personalization Services - Prevents your screen from turning off if you’re looking at it. + Prevents your screen from turning off if you\u2019re looking at it Screen attention uses the front camera to see if someone is looking at the screen. It works on device, and images are never stored or sent to Google. - + + Keep screen on when viewing it Night Light @@ -2912,7 +2924,7 @@ Customize your Pixel - Try different styles, wallpapers, clocks, and more + Try different styles, wallpapers, and more Screen saver @@ -4052,12 +4064,12 @@ PIN has been set Pattern has been set - - To use face authentication, set password - - To use face authentication, set pattern - - To use face authentication, set PIN + + To use face unlock, set password + + To use face unlock, set pattern + + To use face unlock, set PIN @@ -4873,6 +4885,8 @@ Got it The Accessibility button is set to %1$s. To use magnification, touch & hold the Accessibility button, then select magnification. + + The accessibility gesture is set to the %1$s. To use magnification, swipe up with two fingers from the bottom of the screen and hold. Then select magnification. Volume key shortcut @@ -4949,6 +4963,8 @@ Use color correction Use captions + + Not all apps support this setting. Continue @@ -7993,6 +8009,15 @@ Lock screen + + Skip lock screen + + + After face unlock, go directly to last used screen + + + Lock screen, Lockscreen, Skip, Bypass + When work profile is locked @@ -10000,12 +10025,6 @@ Theming - - Accent color - - Headline / Body font - - Icon shape Device default diff --git a/res/xml/adaptive_sleep_detail.xml b/res/xml/adaptive_sleep_detail.xml index 606bb55d465..568e6944581 100644 --- a/res/xml/adaptive_sleep_detail.xml +++ b/res/xml/adaptive_sleep_detail.xml @@ -28,6 +28,14 @@ settings:preview="@drawable/adaptive_sleep" settings:controller="com.android.settings.widget.VideoPreferenceController"/> + + - + + + + + diff --git a/res/xml/configure_notification_settings.xml b/res/xml/configure_notification_settings.xml index 63f67510490..89464fbc5db 100644 --- a/res/xml/configure_notification_settings.xml +++ b/res/xml/configure_notification_settings.xml @@ -72,6 +72,13 @@ android:summary="@string/lock_screen_notifs_redact_work_summary" settings:controller="com.android.settings.notification.RedactNotificationPreferenceController" /> + + + android:order="1100"> - - - - - - - diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml index ad06e959aed..c45e6a2ae10 100644 --- a/res/xml/display_settings.xml +++ b/res/xml/display_settings.xml @@ -93,6 +93,7 @@ - + settings:controller="com.android.settings.security.screenlock.LockScreenPreferenceController" /> - @@ -30,6 +32,6 @@ - + diff --git a/res/xml/security_lockscreen_settings.xml b/res/xml/security_lockscreen_settings.xml index 611d33fee57..8cd4d76fbe0 100644 --- a/res/xml/security_lockscreen_settings.xml +++ b/res/xml/security_lockscreen_settings.xml @@ -30,6 +30,13 @@ android:summary="@string/summary_placeholder" settings:keywords="@string/keywords_lock_screen_notif"/> + + - + settings:controller="com.android.settings.display.AmbientDisplayAlwaysOnPreferenceController" + settings:userRestriction="no_ambient_display" /> @@ -39,18 +40,17 @@ android:title="@string/security_settings_face_settings_use_face_for_apps" app:keywords="@string/keywords_face_unlock" app:controller="com.android.settings.biometrics.face.FaceSettingsAppPreferenceController"/> + - - mPreferenceList = new ArrayList<>(); + @Override public int getMetricsCategory() { return SettingsEnums.ACCESSIBILITY_CAPTION_PROPERTIES; @@ -110,31 +111,18 @@ public class CaptionPropertiesFragment extends SettingsPreferenceFragment updateAllPreferences(); refreshShowingCustom(); installUpdateListeners(); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - final boolean enabled = mCaptioningManager.isEnabled(); - SettingsActivity activity = (SettingsActivity) getActivity(); - mSwitchBar = activity.getSwitchBar(); - mSwitchBar.setSwitchBarText(R.string.accessibility_caption_master_switch_title, - R.string.accessibility_caption_master_switch_title); - mSwitchBar.setCheckedInternal(enabled); - mToggleSwitch = mSwitchBar.getSwitch(); - - getPreferenceScreen().setEnabled(enabled); - refreshPreviewText(); - - installSwitchBarToggleSwitch(); } - @Override - public void onDestroyView() { - super.onDestroyView(); - removeSwitchBarToggleSwitch(); + private void setPreferenceViewEnabled(boolean enabled) { + for (Preference preference : mPreferenceList) { + preference.setEnabled(enabled); + } + } + + private void refreshPreferenceViewEnabled(boolean enabled) { + setPreferenceViewEnabled(enabled); + mPreviewText.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE); } private void refreshPreviewText() { @@ -196,38 +184,10 @@ public class CaptionPropertiesFragment extends SettingsPreferenceFragment } } - protected void onInstallSwitchBarToggleSwitch() { - mToggleSwitch.setOnBeforeCheckedChangeListener(new OnBeforeCheckedChangeListener() { - @Override - public boolean onBeforeCheckedChanged(ToggleSwitch toggleSwitch, boolean checked) { - mSwitchBar.setCheckedInternal(checked); - Settings.Secure.putInt(getActivity().getContentResolver(), - Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, checked ? 1 : 0); - getPreferenceScreen().setEnabled(checked); - if (mPreviewText != null) { - mPreviewText.setVisibility(checked ? View.VISIBLE : View.INVISIBLE); - } - return false; - } - }); - } - - private void installSwitchBarToggleSwitch() { - onInstallSwitchBarToggleSwitch(); - mSwitchBar.show(); - } - - private void removeSwitchBarToggleSwitch() { - mSwitchBar.hide(); - mToggleSwitch.setOnBeforeCheckedChangeListener(null); - } - private void initializeAllPreferences() { final LayoutPreference captionPreview = findPreference(PREF_CAPTION_PREVIEW); - final boolean enabled = mCaptioningManager.isEnabled(); mPreviewText = captionPreview.findViewById(R.id.preview_text); - mPreviewText.setVisibility(enabled ? View.VISIBLE : View.INVISIBLE); mPreviewWindow = captionPreview.findViewById(R.id.preview_window); @@ -236,9 +196,6 @@ public class CaptionPropertiesFragment extends SettingsPreferenceFragment (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> refreshPreviewText()); - mLocale = (LocalePreference) findPreference(PREF_LOCALE); - mFontSize = (ListPreference) findPreference(PREF_FONT_SIZE); - final Resources res = getResources(); final int[] presetValues = res.getIntArray(R.array.captioning_preset_selector_values); final String[] presetTitles = res.getStringArray(R.array.captioning_preset_selector_titles); @@ -246,6 +203,17 @@ public class CaptionPropertiesFragment extends SettingsPreferenceFragment mPreset.setValues(presetValues); mPreset.setTitles(presetTitles); + mSwitch = (SwitchPreference) findPreference(PREF_SWITCH); + mLocale = (LocalePreference) findPreference(PREF_LOCALE); + mFontSize = (ListPreference) findPreference(PREF_FONT_SIZE); + + // Initialize the preference list + mPreferenceList.add(mLocale); + mPreferenceList.add(mFontSize); + mPreferenceList.add(mPreset); + + refreshPreferenceViewEnabled(mCaptioningManager.isEnabled()); + mCustom = (PreferenceCategory) findPreference(PREF_CUSTOM); mShowingCustom = true; @@ -304,6 +272,7 @@ public class CaptionPropertiesFragment extends SettingsPreferenceFragment mWindowOpacity.setOnValueChangedListener(this); mEdgeType.setOnValueChangedListener(this); + mSwitch.setOnPreferenceChangeListener(this); mTypeface.setOnPreferenceChangeListener(this); mFontSize.setOnPreferenceChangeListener(this); mLocale.setOnPreferenceChangeListener(this); @@ -338,6 +307,8 @@ public class CaptionPropertiesFragment extends SettingsPreferenceFragment final String rawLocale = mCaptioningManager.getRawLocale(); mLocale.setValue(rawLocale == null ? "" : rawLocale); + + mSwitch.setChecked(mCaptioningManager.isEnabled()); } /** @@ -431,16 +402,22 @@ public class CaptionPropertiesFragment extends SettingsPreferenceFragment if (mTypeface == preference) { Settings.Secure.putString( cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_TYPEFACE, (String) value); + refreshPreviewText(); } else if (mFontSize == preference) { Settings.Secure.putFloat( cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE, Float.parseFloat((String) value)); + refreshPreviewText(); } else if (mLocale == preference) { Settings.Secure.putString( cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_LOCALE, (String) value); + refreshPreviewText(); + } else if (mSwitch == preference) { + Settings.Secure.putInt( + cr, Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED, (boolean) value ? 1 : 0); + refreshPreferenceViewEnabled((boolean) value); } - refreshPreviewText(); return true; } } diff --git a/src/com/android/settings/accessibility/MagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/MagnificationPreferenceFragment.java index c3cb34fbcbc..b96d2b76725 100644 --- a/src/com/android/settings/accessibility/MagnificationPreferenceFragment.java +++ b/src/com/android/settings/accessibility/MagnificationPreferenceFragment.java @@ -16,6 +16,8 @@ package com.android.settings.accessibility; +import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; + import android.accessibilityservice.AccessibilityServiceInfo; import android.app.settings.SettingsEnums; import android.content.ComponentName; @@ -132,9 +134,10 @@ public final class MagnificationPreferenceFragment extends DashboardFragment { if (info.getComponentName().equals(assignedComponentName)) { final CharSequence assignedServiceName = info.getResolveInfo().loadLabel( context.getPackageManager()); - return context.getString( - R.string.accessibility_screen_magnification_navbar_configuration_warning, - assignedServiceName); + final int messageId = isGestureNavigateEnabled(context) + ? R.string.accessibility_screen_magnification_gesture_navigation_warning + : R.string.accessibility_screen_magnification_navbar_configuration_warning; + return context.getString(messageId, assignedServiceName); } } } @@ -158,6 +161,12 @@ public final class MagnificationPreferenceFragment extends DashboardFragment { return res.getBoolean(com.android.internal.R.bool.config_showNavigationBar); } + private static boolean isGestureNavigateEnabled(Context context) { + return context.getResources().getInteger( + com.android.internal.R.integer.config_navBarInteractionMode) + == NAV_BAR_MODE_GESTURAL; + } + public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = new BaseSearchIndexProvider() { @Override @@ -173,4 +182,4 @@ public final class MagnificationPreferenceFragment extends DashboardFragment { return isApplicable(context.getResources()); } }; -} +} \ No newline at end of file diff --git a/src/com/android/settings/applications/appinfo/AppStoragePreferenceController.java b/src/com/android/settings/applications/appinfo/AppStoragePreferenceController.java index d887634a540..b0d49390cd0 100644 --- a/src/com/android/settings/applications/appinfo/AppStoragePreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppStoragePreferenceController.java @@ -31,6 +31,7 @@ import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.applications.AppStorageSettings; import com.android.settings.applications.FetchPackageStorageAsyncLoader; +import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.StorageStatsSource; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; @@ -48,9 +49,12 @@ public class AppStoragePreferenceController extends AppInfoPreferenceControllerB @Override public void updateState(Preference preference) { - final boolean isExternal = - (mParent.getAppEntry().info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; - preference.setSummary(getStorageSummary(mLastResult, isExternal)); + final ApplicationsState.AppEntry entry = mParent.getAppEntry(); + if (entry != null && entry.info != null) { + final boolean isExternal = + (entry.info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0; + preference.setSummary(getStorageSummary(mLastResult, isExternal)); + } } @Override diff --git a/src/com/android/settings/biometrics/BiometricEnrollBase.java b/src/com/android/settings/biometrics/BiometricEnrollBase.java index c3f794f6905..c23aee659cc 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollBase.java +++ b/src/com/android/settings/biometrics/BiometricEnrollBase.java @@ -172,11 +172,11 @@ public abstract class BiometricEnrollBase extends InstrumentedActivity { if (mUserId == UserHandle.USER_NULL) { launchedConfirmationActivity = helper.launchConfirmationActivity(CONFIRM_REQUEST, getString(titleResId), - null, null, challenge); + null, null, challenge, true /* foregroundOnly */); } else { launchedConfirmationActivity = helper.launchConfirmationActivity(CONFIRM_REQUEST, getString(titleResId), - null, null, challenge, mUserId); + null, null, challenge, mUserId, true /* foregroundOnly */); } if (!launchedConfirmationActivity) { // This shouldn't happen, as we should only end up at this step if a lock thingy is diff --git a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java index d5414c9664d..d94686e3f27 100644 --- a/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/BiometricEnrollIntroduction.java @@ -47,6 +47,8 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase private boolean mHasPassword; private boolean mBiometricUnlockDisabledByAdmin; private TextView mErrorText; + protected boolean mConfirmingCredentials; + protected boolean mNextClicked; /** * @return true if the biometric is disabled by a device administrator @@ -149,10 +151,12 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase if (!mHasPassword) { // No password registered, launch into enrollment wizard. + mConfirmingCredentials = true; launchChooseLock(); } else if (mToken == null) { // It's possible to have a token but mLaunchedConfirmLock == false, since // ChooseLockGeneric can pass us a token. + mConfirmingCredentials = true; launchConfirmLock(getConfirmLockTitleResId(), getChallenge()); } } @@ -182,6 +186,7 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase @Override protected void onNextButtonClick(View view) { + mNextClicked = true; if (checkMaxEnrolled() == 0) { // Lock thingy is already set up, launch directly to the next page launchNextEnrollingActivity(mToken); @@ -249,12 +254,14 @@ public abstract class BiometricEnrollIntroduction extends BiometricEnrollBase mToken = data.getByteArrayExtra( ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); + mConfirmingCredentials = false; return; } else { setResult(resultCode, data); finish(); } } else if (requestCode == CONFIRM_REQUEST) { + mConfirmingCredentials = false; if (resultCode == RESULT_OK && data != null) { mToken = data.getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out); diff --git a/src/com/android/settings/biometrics/face/FaceEnrollAccessibilityToggle.java b/src/com/android/settings/biometrics/face/FaceEnrollAccessibilityToggle.java index dffc67de169..f6ba0f989e5 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollAccessibilityToggle.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollAccessibilityToggle.java @@ -60,6 +60,8 @@ public class FaceEnrollAccessibilityToggle extends LinearLayout { } mSwitch = findViewById(R.id.toggle); mSwitch.setChecked(false); + mSwitch.setClickable(false); + mSwitch.setFocusable(false); } public boolean isChecked() { diff --git a/src/com/android/settings/biometrics/face/FaceEnrollEducation.java b/src/com/android/settings/biometrics/face/FaceEnrollEducation.java index 956ba49d6be..e1253c14796 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollEducation.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollEducation.java @@ -16,7 +16,6 @@ package com.android.settings.biometrics.face; -import static android.provider.Settings.Secure.FACE_UNLOCK_EDUCATION_INFO_DISPLAYED; import static android.security.KeyStore.getApplicationContext; import android.app.settings.SettingsEnums; @@ -50,8 +49,6 @@ public class FaceEnrollEducation extends BiometricEnrollBase { private static final String TAG = "FaceEducation"; private static final int ON = 1; private static final int OFF = 0; - // 8 seconds. - private static final long FACE_ENROLL_EDUCATION_DELAY = 8000; private FaceManager mFaceManager; private FaceEnrollAccessibilityToggle mSwitchDiversity; @@ -61,6 +58,7 @@ public class FaceEnrollEducation extends BiometricEnrollBase { private Handler mHandler; private Intent mResultIntent; private TextView mDescriptionText; + private boolean mNextClicked; private CompoundButton.OnCheckedChangeListener mSwitchDiversityListener = new CompoundButton.OnCheckedChangeListener() { @@ -101,14 +99,26 @@ public class FaceEnrollEducation extends BiometricEnrollBase { mDescriptionText = findViewById(R.id.sud_layout_description); mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class); - mFooterBarMixin.setSecondaryButton( - new FooterButton.Builder(this) - .setText(R.string.security_settings_face_enroll_enrolling_skip) - .setListener(this::onSkipButtonClick) - .setButtonType(FooterButton.ButtonType.SKIP) - .setTheme(R.style.SudGlifButton_Secondary) - .build() - ); + + if (WizardManagerHelper.isAnySetupWizard(getIntent())) { + mFooterBarMixin.setSecondaryButton( + new FooterButton.Builder(this) + .setText(R.string.skip_label) + .setListener(this::onSkipButtonClick) + .setButtonType(FooterButton.ButtonType.SKIP) + .setTheme(R.style.SudGlifButton_Secondary) + .build() + ); + } else { + mFooterBarMixin.setSecondaryButton( + new FooterButton.Builder(this) + .setText(R.string.security_settings_face_enroll_introduction_cancel) + .setListener(this::onSkipButtonClick) + .setButtonType(FooterButton.ButtonType.CANCEL) + .setTheme(R.style.SudGlifButton_Secondary) + .build() + ); + } final FooterButton footerButton = new FooterButton.Builder(this) .setText(R.string.security_settings_face_enroll_education_start) @@ -121,24 +131,15 @@ public class FaceEnrollEducation extends BiometricEnrollBase { final AccessibilityManager accessibilityManager = getApplicationContext().getSystemService( AccessibilityManager.class); if (accessibilityManager != null) { - accessibilityEnabled = accessibilityManager.isEnabled(); + // Add additional check for touch exploration. This prevents other accessibility + // features such as Live Transcribe from defaulting to the accessibility setup. + accessibilityEnabled = accessibilityManager.isEnabled() + && accessibilityManager.isTouchExplorationEnabled(); } mFooterBarMixin.setPrimaryButton(footerButton); - final Context context = getApplicationContext(); - final boolean didDisplayEdu = Settings.Secure.getIntForUser(context.getContentResolver(), - FACE_UNLOCK_EDUCATION_INFO_DISPLAYED, OFF, mUserId) == ON; - if (!didDisplayEdu && !accessibilityEnabled) { - Settings.Secure.putIntForUser(context.getContentResolver(), - FACE_UNLOCK_EDUCATION_INFO_DISPLAYED, ON, mUserId); - footerButton.setEnabled(false); - mHandler.postDelayed(() -> { - footerButton.setEnabled(true); - }, FACE_ENROLL_EDUCATION_DELAY); - } final Button accessibilityButton = findViewById(R.id.accessibility_button); accessibilityButton.setOnClickListener(view -> { - footerButton.setEnabled(true); mSwitchDiversity.setChecked(true); accessibilityButton.setVisibility(View.GONE); mSwitchDiversity.setVisibility(View.VISIBLE); @@ -146,6 +147,9 @@ public class FaceEnrollEducation extends BiometricEnrollBase { mSwitchDiversity = findViewById(R.id.toggle_diversity); mSwitchDiversity.setListener(mSwitchDiversityListener); + mSwitchDiversity.setOnClickListener(v -> { + mSwitchDiversity.getSwitch().toggle(); + }); if (accessibilityEnabled) { accessibilityButton.callOnClick(); @@ -157,6 +161,26 @@ public class FaceEnrollEducation extends BiometricEnrollBase { super.onResume(); mSwitchDiversityListener.onCheckedChanged(mSwitchDiversity.getSwitch(), mSwitchDiversity.isChecked()); + + // If the user goes back after enrollment, we should send them back to the intro page + // if they've met the max limit. + final int max = getResources().getInteger( + com.android.internal.R.integer.config_faceMaxTemplatesPerUser); + final int numEnrolledFaces = mFaceManager.getEnrolledFaces(mUserId).size(); + if (numEnrolledFaces >= max) { + finish(); + } + } + + @Override + protected void onStop() { + super.onStop(); + + if (!isChangingConfigurations() && !WizardManagerHelper.isAnySetupWizard(getIntent()) + && !mNextClicked) { + setResult(RESULT_SKIP); + finish(); + } } @Override @@ -168,6 +192,7 @@ public class FaceEnrollEducation extends BiometricEnrollBase { if (mUserId != UserHandle.USER_NULL) { intent.putExtra(Intent.EXTRA_USER_ID, mUserId); } + intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, mFromSettingsSummary); final String flattenedString = getString(R.string.config_face_enroll); if (!TextUtils.isEmpty(flattenedString)) { ComponentName componentName = ComponentName.unflattenFromString(flattenedString); @@ -175,11 +200,12 @@ public class FaceEnrollEducation extends BiometricEnrollBase { } else { intent.setClass(this, FaceEnrollEnrolling.class); } - intent.putExtra(EXTRA_KEY_REQUIRE_DIVERSITY, !mSwitchDiversity.isChecked()); + WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent); if (mResultIntent != null) { intent.putExtras(mResultIntent); } - WizardManagerHelper.copyWizardManagerExtras(getIntent(), intent); + mNextClicked = true; + intent.putExtra(EXTRA_KEY_REQUIRE_DIVERSITY, !mSwitchDiversity.isChecked()); startActivityForResult(intent, BIOMETRIC_FIND_SENSOR_REQUEST); } diff --git a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java index ea2fa5c438b..bf4a1d46187 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollEnrolling.java @@ -32,6 +32,7 @@ import com.android.settings.biometrics.BiometricEnrollBase; import com.android.settings.biometrics.BiometricEnrollSidecar; import com.android.settings.biometrics.BiometricErrorDialog; import com.android.settings.biometrics.BiometricsEnrollEnrolling; +import com.android.settings.slices.CustomSliceRegistry; import com.google.android.setupcompat.template.FooterBarMixin; import com.google.android.setupcompat.template.FooterButton; @@ -184,6 +185,10 @@ public class FaceEnrollEnrolling extends BiometricsEnrollEnrolling { // TODO: Have this match any animations that UX comes up with if (remaining == 0) { + // Force the reload of the FaceEnroll slice in case a user has enrolled, + // this will cause the slice to no longer appear. + getApplicationContext().getContentResolver().notifyChange( + CustomSliceRegistry.FACE_ENROLL_SLICE_URI, null); launchFinish(mToken); } } diff --git a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java index 525c1a3ee42..6686c96f928 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollIntroduction.java @@ -77,6 +77,16 @@ public class FaceEnrollIntroduction extends BiometricEnrollIntroduction { ); } + @Override + protected void onStop() { + super.onStop(); + + if (!isChangingConfigurations() && !mConfirmingCredentials && !mNextClicked + && !WizardManagerHelper.isAnySetupWizard(getIntent())) { + finish(); + } + } + @Override protected boolean isDisabledByAdmin() { return RestrictedLockUtilsInternal.checkIfKeyguardFeaturesDisabled( diff --git a/src/com/android/settings/biometrics/face/FaceEnrollSidecar.java b/src/com/android/settings/biometrics/face/FaceEnrollSidecar.java index c75f300aa8e..512d8fe4de6 100644 --- a/src/com/android/settings/biometrics/face/FaceEnrollSidecar.java +++ b/src/com/android/settings/biometrics/face/FaceEnrollSidecar.java @@ -52,7 +52,7 @@ public class FaceEnrollSidecar extends BiometricEnrollSidecar { mFaceManager.setActiveUser(mUserId); } - mFaceManager.enroll(mToken, mEnrollmentCancel, + mFaceManager.enroll(mUserId, mToken, mEnrollmentCancel, mEnrollmentCallback, mDisabledFeatures); } diff --git a/src/com/android/settings/biometrics/face/FaceProfileStatusPreferenceController.java b/src/com/android/settings/biometrics/face/FaceProfileStatusPreferenceController.java index 196992dbd9d..56b325bdf89 100644 --- a/src/com/android/settings/biometrics/face/FaceProfileStatusPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceProfileStatusPreferenceController.java @@ -19,14 +19,30 @@ package com.android.settings.biometrics.face; import android.content.Context; import android.os.UserHandle; +import com.android.settings.R; + +import androidx.preference.Preference; + public class FaceProfileStatusPreferenceController extends FaceStatusPreferenceController { - public static final String KEY_FACE_SETTINGS = "face_settings_profile"; + private static final String KEY_FACE_SETTINGS = "face_settings_profile"; public FaceProfileStatusPreferenceController(Context context) { super(context, KEY_FACE_SETTINGS); } + @Override + public int getAvailabilityStatus() { + // Check if Face for Profile is available. + final int isAvailable = super.getAvailabilityStatus(); + if (isAvailable != AVAILABLE) { + return isAvailable; + } + // Make the profile unsearchable so the user preference controller gets highlighted + // when searched for. + return AVAILABLE_UNSEARCHABLE; + } + @Override protected boolean isUserSupported() { return mProfileChallengeUserId != UserHandle.USER_NULL @@ -37,4 +53,11 @@ public class FaceProfileStatusPreferenceController extends FaceStatusPreferenceC protected int getUserId() { return mProfileChallengeUserId; } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + preference.setTitle(mContext.getResources().getString( + R.string.security_settings_face_profile_preference_title)); + } } diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java index 48370d9fb78..b8bb030bc43 100644 --- a/src/com/android/settings/biometrics/face/FaceSettings.java +++ b/src/com/android/settings/biometrics/face/FaceSettings.java @@ -60,7 +60,6 @@ public class FaceSettings extends DashboardFragment { private FaceManager mFaceManager; private int mUserId; private byte[] mToken; - private FaceSettingsAttentionPreferenceController mAttentionController; private FaceSettingsRemoveButtonPreferenceController mRemoveController; private FaceSettingsEnrollButtonPreferenceController mEnrollController; private List mControllers; @@ -69,6 +68,8 @@ public class FaceSettings extends DashboardFragment { private Preference mRemoveButton; private Preference mEnrollButton; + private boolean mConfirmingPassword; + private final FaceSettingsRemoveButtonPreferenceController.Listener mRemovalListener = () -> { // Disable the toggles until the user re-enrolls @@ -117,12 +118,18 @@ public class FaceSettings extends DashboardFragment { mUserId = getActivity().getIntent().getIntExtra( Intent.EXTRA_USER_ID, UserHandle.myUserId()); + if (mUserManager.getUserInfo(mUserId).isManagedProfile()) { + getActivity().setTitle(getActivity().getResources().getString( + R.string.security_settings_face_profile_preference_title)); + } + Preference keyguardPref = findPreference(FaceSettingsKeyguardPreferenceController.KEY); Preference appPref = findPreference(FaceSettingsAppPreferenceController.KEY); - Preference attentionPref = findPreference(FaceSettingsAttentionPreferenceController.KEY); Preference confirmPref = findPreference(FaceSettingsConfirmPreferenceController.KEY); + Preference bypassPref = + findPreference(FaceSettingsLockscreenBypassPreferenceController.KEY); mTogglePreferences = new ArrayList<>( - Arrays.asList(keyguardPref, appPref, attentionPref, confirmPref)); + Arrays.asList(keyguardPref, appPref, confirmPref, bypassPref)); mRemoveButton = findPreference(FaceSettingsRemoveButtonPreferenceController.KEY); mEnrollButton = findPreference(FaceSettingsEnrollButtonPreferenceController.KEY); @@ -145,24 +152,27 @@ public class FaceSettings extends DashboardFragment { if (savedInstanceState != null) { mToken = savedInstanceState.getByteArray(KEY_TOKEN); } - - if (mToken == null) { - final long challenge = mFaceManager.generateChallenge(); - ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(getActivity(), this); - if (!helper.launchConfirmationActivity(CONFIRM_REQUEST, - getString(R.string.security_settings_face_preference_title), - null, null, challenge, mUserId)) { - Log.e(TAG, "Password not set"); - finish(); - } - } } @Override public void onResume() { super.onResume(); - if (mToken != null) { - mAttentionController.setToken(mToken); + + if (mToken == null && !mConfirmingPassword) { + // Generate challenge in onResume instead of onCreate, since FaceSettings can be + // created while Keyguard is showing, in which case the resetLockout revokeChallenge + // will invalidate the too-early created challenge here. + final long challenge = mFaceManager.generateChallenge(); + ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(getActivity(), this); + + mConfirmingPassword = true; + if (!helper.launchConfirmationActivity(CONFIRM_REQUEST, + getString(R.string.security_settings_face_preference_title), + null, null, challenge, mUserId, true /* foregroundOnly */)) { + Log.e(TAG, "Password not set"); + finish(); + } + } else { mEnrollController.setToken(mToken); } @@ -175,6 +185,7 @@ public class FaceSettings extends DashboardFragment { public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == CONFIRM_REQUEST) { + mConfirmingPassword = false; if (resultCode == RESULT_FINISHED || resultCode == RESULT_OK) { mFaceManager.setActiveUser(mUserId); // The pin/pattern/password was set. @@ -182,7 +193,6 @@ public class FaceSettings extends DashboardFragment { mToken = data.getByteArrayExtra( ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); if (mToken != null) { - mAttentionController.setToken(mToken); mEnrollController.setToken(mToken); } } @@ -196,16 +206,28 @@ public class FaceSettings extends DashboardFragment { } @Override - public void onDestroy() { - super.onDestroy(); - if (getActivity().isFinishing()) { - final int result = mFaceManager.revokeChallenge(); - if (result < 0) { - Log.w(TAG, "revokeChallenge failed, result: " + result); + public void onStop() { + super.onStop(); + + if (!mEnrollController.isClicked() && !getActivity().isChangingConfigurations() + && !mConfirmingPassword) { + // Revoke challenge and finish + if (mToken != null) { + final int result = mFaceManager.revokeChallenge(); + if (result < 0) { + Log.w(TAG, "revokeChallenge failed, result: " + result); + } + mToken = null; } + getActivity().finish(); } } + @Override + public int getHelpResource() { + return R.string.help_url_face; + } + @Override protected List createPreferenceControllers(Context context) { if (!isAvailable(context)) { @@ -214,9 +236,7 @@ public class FaceSettings extends DashboardFragment { mControllers = buildPreferenceControllers(context, getSettingsLifecycle()); // There's no great way of doing this right now :/ for (AbstractPreferenceController controller : mControllers) { - if (controller instanceof FaceSettingsAttentionPreferenceController) { - mAttentionController = (FaceSettingsAttentionPreferenceController) controller; - } else if (controller instanceof FaceSettingsRemoveButtonPreferenceController) { + if (controller instanceof FaceSettingsRemoveButtonPreferenceController) { mRemoveController = (FaceSettingsRemoveButtonPreferenceController) controller; mRemoveController.setListener(mRemovalListener); mRemoveController.setActivity((SettingsActivity) getActivity()); @@ -235,7 +255,6 @@ public class FaceSettings extends DashboardFragment { controllers.add(new FaceSettingsVideoPreferenceController(context)); controllers.add(new FaceSettingsKeyguardPreferenceController(context)); controllers.add(new FaceSettingsAppPreferenceController(context)); - controllers.add(new FaceSettingsAttentionPreferenceController(context)); controllers.add(new FaceSettingsRemoveButtonPreferenceController(context)); controllers.add(new FaceSettingsFooterPreferenceController(context)); controllers.add(new FaceSettingsConfirmPreferenceController(context)); diff --git a/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java index 70c00e54d28..a54171e8c42 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsAppPreferenceController.java @@ -78,6 +78,19 @@ public class FaceSettingsAppPreferenceController extends FaceSettingsPreferenceC @Override public int getAvailabilityStatus() { - return AVAILABLE; + if(mFaceManager == null){ + return AVAILABLE_UNSEARCHABLE; + } + + // By only allowing this preference controller to be searchable when the feature is turned + // off, it will give preference to the face setup controller. + final boolean hasEnrolledUser = mFaceManager.hasEnrolledTemplates(getUserId()); + final boolean appUnlockEnabled = Settings.Secure.getIntForUser( + mContext.getContentResolver(), FACE_UNLOCK_APP_ENABLED, OFF, getUserId()) == ON; + if (hasEnrolledUser && !appUnlockEnabled) { + return AVAILABLE; + } else { + return AVAILABLE_UNSEARCHABLE; + } } } diff --git a/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java index ef90b1eda34..9ae6a874b0a 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java @@ -99,7 +99,8 @@ public class FaceSettingsAttentionPreferenceController extends FaceSettingsPrefe } // Set to disabled until we know the true value. mPreference.setEnabled(false); - mFaceManager.getFeature(FaceManager.FEATURE_REQUIRE_ATTENTION, mGetFeatureCallback); + mFaceManager.getFeature(getUserId(), FaceManager.FEATURE_REQUIRE_ATTENTION, + mGetFeatureCallback); // Ideally returns a cached value. return true; @@ -111,8 +112,8 @@ public class FaceSettingsAttentionPreferenceController extends FaceSettingsPrefe mPreference.setEnabled(false); mPreference.setChecked(isChecked); - mFaceManager.setFeature(FaceManager.FEATURE_REQUIRE_ATTENTION, isChecked, mToken, - mSetFeatureCallback); + mFaceManager.setFeature(getUserId(), FaceManager.FEATURE_REQUIRE_ATTENTION, isChecked, + mToken, mSetFeatureCallback); return true; } diff --git a/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java index ec7b1948fea..a087ccc78e4 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsEnrollButtonPreferenceController.java @@ -42,6 +42,7 @@ public class FaceSettingsEnrollButtonPreferenceController extends BasePreference private byte[] mToken; private SettingsActivity mActivity; private Button mButton; + private boolean mIsClicked; public FaceSettingsEnrollButtonPreferenceController(Context context) { this(context, KEY); @@ -63,6 +64,7 @@ public class FaceSettingsEnrollButtonPreferenceController extends BasePreference @Override public void onClick(View v) { + mIsClicked = true; final Intent intent = new Intent(); intent.setClassName("com.android.settings", FaceEnrollIntroduction.class.getName()); intent.putExtra(Intent.EXTRA_USER_ID, mUserId); @@ -83,6 +85,13 @@ public class FaceSettingsEnrollButtonPreferenceController extends BasePreference mToken = token; } + // Return the click state, then clear its state. + public boolean isClicked() { + final boolean wasClicked = mIsClicked; + mIsClicked = false; + return wasClicked; + } + public void setActivity(SettingsActivity activity) { mActivity = activity; } diff --git a/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java index c64455af30b..9ec1ad1eb74 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsKeyguardPreferenceController.java @@ -18,16 +18,13 @@ package com.android.settings.biometrics.face; import static android.provider.Settings.Secure.FACE_UNLOCK_KEYGUARD_ENABLED; -import android.app.admin.DevicePolicyManager; import android.content.Context; import android.hardware.face.FaceManager; -import android.os.UserHandle; import android.provider.Settings; import androidx.preference.Preference; import com.android.settings.Utils; -import com.android.settings.core.TogglePreferenceController; /** * Preference controller for Face settings page controlling the ability to unlock the phone @@ -87,13 +84,4 @@ public class FaceSettingsKeyguardPreferenceController extends FaceSettingsPrefer preference.setEnabled(true); } } - - private boolean adminDisabled() { - DevicePolicyManager dpm = - (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); - return dpm != null && - (dpm.getKeyguardDisabledFeatures(null, UserHandle.myUserId()) - & DevicePolicyManager.KEYGUARD_DISABLE_FACE) - != 0; - } } diff --git a/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceController.java new file mode 100644 index 00000000000..15fab260dc9 --- /dev/null +++ b/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceController.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2019 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.biometrics.face; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.hardware.face.FaceManager; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; + +import androidx.preference.Preference; + +import com.android.internal.annotations.VisibleForTesting; + +public class FaceSettingsLockscreenBypassPreferenceController + extends FaceSettingsPreferenceController { + + static final String KEY = "security_lockscreen_bypass"; + + @VisibleForTesting + protected FaceManager mFaceManager; + private UserManager mUserManager; + + public FaceSettingsLockscreenBypassPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) { + mFaceManager = context.getSystemService(FaceManager.class); + } + + mUserManager = context.getSystemService(UserManager.class); + } + + @Override + public boolean isChecked() { + boolean defaultValue = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_faceAuthDismissesKeyguard); + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, defaultValue ? 1 : 0) != 0; + } + + @Override + public boolean setChecked(boolean isChecked) { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, isChecked ? 1 : 0); + return true; + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + if (!FaceSettings.isAvailable(mContext)) { + preference.setEnabled(false); + } else if (adminDisabled()) { + preference.setEnabled(false); + } else if (!mFaceManager.hasEnrolledTemplates(getUserId())) { + preference.setEnabled(false); + } else { + preference.setEnabled(true); + } + } + + @Override + public int getAvailabilityStatus() { + if (mUserManager.isManagedProfile(UserHandle.myUserId())) { + return UNSUPPORTED_ON_DEVICE; + } + + if (mFaceManager != null && mFaceManager.isHardwareDetected()) { + return mFaceManager.hasEnrolledTemplates() ? AVAILABLE : DISABLED_DEPENDENT_SETTING; + } else { + return UNSUPPORTED_ON_DEVICE; + } + } +} diff --git a/src/com/android/settings/biometrics/face/FaceSettingsPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsPreferenceController.java index b8ac118551e..55e093ba79a 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsPreferenceController.java @@ -16,7 +16,9 @@ package com.android.settings.biometrics.face; +import android.app.admin.DevicePolicyManager; import android.content.Context; +import android.os.UserHandle; import com.android.settings.core.TogglePreferenceController; @@ -38,4 +40,13 @@ public abstract class FaceSettingsPreferenceController extends TogglePreferenceC protected int getUserId() { return mUserId; } + + protected boolean adminDisabled() { + DevicePolicyManager dpm = + (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + return dpm != null && + (dpm.getKeyguardDisabledFeatures(null, UserHandle.myUserId()) + & DevicePolicyManager.KEYGUARD_DISABLE_FACE) + != 0; + } } diff --git a/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java index d532a7636f4..1c1b81df6c8 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsRemoveButtonPreferenceController.java @@ -64,7 +64,7 @@ public class FaceSettingsRemoveButtonPreferenceController extends BasePreference builder.setTitle(R.string.security_settings_face_settings_remove_dialog_title) .setMessage(R.string.security_settings_face_settings_remove_dialog_details) - .setPositiveButton(R.string.okay, mOnClickListener) + .setPositiveButton(R.string.delete, mOnClickListener) .setNegativeButton(R.string.cancel, mOnClickListener); AlertDialog dialog = builder.create(); dialog.setCanceledOnTouchOutside(false); diff --git a/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java b/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java index 84505772092..cb82b5e8563 100644 --- a/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceStatusPreferenceController.java @@ -26,7 +26,7 @@ import com.android.settings.biometrics.BiometricStatusPreferenceController; public class FaceStatusPreferenceController extends BiometricStatusPreferenceController { - private static final String KEY_FACE_SETTINGS = "face_settings"; + public static final String KEY_FACE_SETTINGS = "face_settings"; protected final FaceManager mFaceManager; diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index ad0ae6fd968..3fbcfd4be96 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -617,7 +617,7 @@ public class FingerprintSettings extends SubSettings { ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(getActivity(), this); if (!helper.launchConfirmationActivity(CONFIRM_REQUEST, getString(R.string.security_settings_fingerprint_preference_title), - null, null, challenge, mUserId)) { + null, null, challenge, mUserId, true /* foregroundOnly */)) { intent.setClassName(SETTINGS_PACKAGE_NAME, ChooseLockGeneric.class.getName()); intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING); diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index aba95c80cc7..f384d8570ce 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -494,12 +494,6 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra controllers.add(new DefaultLaunchPreferenceController(context, "inactive_apps")); controllers.add(new AutofillLoggingLevelPreferenceController(context, lifecycle)); controllers.add(new AutofillResetOptionsPreferenceController(context)); - controllers.add(new OverlayCategoryPreferenceController(context, - "android.theme.customization.accent_color")); - controllers.add(new OverlayCategoryPreferenceController(context, - "android.theme.customization.font")); - controllers.add(new OverlayCategoryPreferenceController(context, - "android.theme.customization.adaptive_icon_shape")); controllers.add(new TrustAgentsExtendUnlockPreferenceController(context)); controllers.add(new TrustLostLocksScreenPreferenceController(context)); return controllers; diff --git a/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java index ff9352a7d4b..fd54f19b819 100644 --- a/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java +++ b/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java @@ -21,6 +21,7 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.text.TextUtils; +import android.text.format.DateFormat; import android.util.Log; import androidx.annotation.VisibleForTesting; @@ -28,9 +29,20 @@ import androidx.preference.Preference; import com.android.settings.core.BasePreferenceController; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.TimeZone; + public class MainlineModuleVersionPreferenceController extends BasePreferenceController { private static final String TAG = "MainlineModuleControl"; + private static final List VERSION_NAME_DATE_PATTERNS = Arrays.asList("yyyy-MM-dd", + "yyyy-MM"); @VisibleForTesting static final Intent MODULE_UPDATE_INTENT = @@ -81,6 +93,30 @@ public class MainlineModuleVersionPreferenceController extends BasePreferenceCon @Override public CharSequence getSummary() { - return mModuleVersion; + if (TextUtils.isEmpty(mModuleVersion)) { + return mModuleVersion; + } + + final Optional parsedDate = parseDateFromVersionName(mModuleVersion); + if (!parsedDate.isPresent()) { + Log.w("Could not parse mainline versionName (%s) as date.", mModuleVersion); + return mModuleVersion; + } + + return DateFormat.getLongDateFormat(mContext).format(parsedDate.get()); + } + + private Optional parseDateFromVersionName(String text) { + for (String pattern : VERSION_NAME_DATE_PATTERNS) { + try { + final SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern, + Locale.getDefault()); + simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + return Optional.of(simpleDateFormat.parse(text)); + } catch (ParseException e) { + // ignore and try next pattern + } + } + return Optional.empty(); } } diff --git a/src/com/android/settings/display/AdaptiveSleepDetailPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepDetailPreferenceController.java index 5ce7be5b43e..0e2358c806b 100644 --- a/src/com/android/settings/display/AdaptiveSleepDetailPreferenceController.java +++ b/src/com/android/settings/display/AdaptiveSleepDetailPreferenceController.java @@ -21,6 +21,7 @@ import android.content.Context; import androidx.preference.Preference; public class AdaptiveSleepDetailPreferenceController extends AdaptiveSleepPreferenceController { + public AdaptiveSleepDetailPreferenceController(Context context, String key) { super(context, key); } @@ -42,6 +43,6 @@ public class AdaptiveSleepDetailPreferenceController extends AdaptiveSleepPrefer @Override public void updateState(Preference preference) { super.updateState(preference); - preference.setEnabled(super.hasSufficientPermissions); + preference.setEnabled(hasSufficientPermission(mContext.getPackageManager())); } -} +} \ No newline at end of file diff --git a/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceController.java new file mode 100644 index 00000000000..9e6bca453e4 --- /dev/null +++ b/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceController.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2019 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.display; + +import static com.android.settings.display.AdaptiveSleepPreferenceController.hasSufficientPermission; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.text.TextUtils; + +import androidx.preference.Preference; + +import com.android.settings.core.BasePreferenceController; + +public class AdaptiveSleepPermissionPreferenceController extends BasePreferenceController { + final static String PREF_NAME = "adaptive_sleep_permission"; + private final Intent mIntent; + + public AdaptiveSleepPermissionPreferenceController(Context context, String key) { + super(context, key); + final String packageName = context.getPackageManager().getAttentionServicePackageName(); + mIntent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + mIntent.setData(Uri.parse("package:" + packageName)); + } + + @Override + @AvailabilityStatus + public int getAvailabilityStatus() { + return AVAILABLE_UNSEARCHABLE; + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (TextUtils.equals(getPreferenceKey(), preference.getKey())) { + mContext.startActivity(mIntent); + return true; + } + return super.handlePreferenceTreeClick(preference); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + if (TextUtils.equals(getPreferenceKey(), preference.getKey())) { + preference.setVisible(!hasSufficientPermission(mContext.getPackageManager())); + } + } +} diff --git a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java index 6b91792800e..b736b79575f 100644 --- a/src/com/android/settings/display/AdaptiveSleepPreferenceController.java +++ b/src/com/android/settings/display/AdaptiveSleepPreferenceController.java @@ -25,28 +25,20 @@ import com.android.settings.core.TogglePreferenceController; public class AdaptiveSleepPreferenceController extends TogglePreferenceController { - - private final String SYSTEM_KEY = ADAPTIVE_SLEEP; - private final int DEFAULT_VALUE = 0; - - final boolean hasSufficientPermissions; + public static final String PREF_NAME = "adaptive_sleep"; + private static final String SYSTEM_KEY = ADAPTIVE_SLEEP; + private static final int DEFAULT_VALUE = 0; public AdaptiveSleepPreferenceController(Context context, String key) { super(context, key); - - final PackageManager packageManager = mContext.getPackageManager(); - final String attentionPackage = packageManager.getAttentionServicePackageName(); - hasSufficientPermissions = attentionPackage != null && packageManager.checkPermission( - Manifest.permission.CAMERA, attentionPackage) == PackageManager.PERMISSION_GRANTED; } @Override public boolean isChecked() { - return hasSufficientPermissions && Settings.System.getInt(mContext.getContentResolver(), - SYSTEM_KEY, DEFAULT_VALUE) != DEFAULT_VALUE; + return hasSufficientPermission(mContext.getPackageManager()) && Settings.System.getInt( + mContext.getContentResolver(), SYSTEM_KEY, DEFAULT_VALUE) != DEFAULT_VALUE; } - @Override public boolean setChecked(boolean isChecked) { Settings.System.putInt(mContext.getContentResolver(), SYSTEM_KEY, @@ -57,10 +49,7 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle @Override @AvailabilityStatus public int getAvailabilityStatus() { - return mContext.getResources().getBoolean( - com.android.internal.R.bool.config_adaptive_sleep_available) - ? AVAILABLE_UNSEARCHABLE - : UNSUPPORTED_ON_DEVICE; + return isControllerAvailable(mContext); } @Override @@ -69,4 +58,17 @@ public class AdaptiveSleepPreferenceController extends TogglePreferenceControlle ? R.string.adaptive_sleep_summary_on : R.string.adaptive_sleep_summary_off); } + + public static int isControllerAvailable(Context context) { + return context.getResources().getBoolean( + com.android.internal.R.bool.config_adaptive_sleep_available) + ? AVAILABLE_UNSEARCHABLE + : UNSUPPORTED_ON_DEVICE; + } + + static boolean hasSufficientPermission(PackageManager packageManager) { + final String attentionPackage = packageManager.getAttentionServicePackageName(); + return attentionPackage != null && packageManager.checkPermission( + Manifest.permission.CAMERA, attentionPackage) == PackageManager.PERMISSION_GRANTED; + } } diff --git a/src/com/android/settings/display/AdaptiveSleepSettings.java b/src/com/android/settings/display/AdaptiveSleepSettings.java index 4c17a67b717..66e20b4b8fd 100644 --- a/src/com/android/settings/display/AdaptiveSleepSettings.java +++ b/src/com/android/settings/display/AdaptiveSleepSettings.java @@ -16,11 +16,16 @@ package com.android.settings.display; +import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF; +import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF_KEY_INTERACTED; + import android.app.settings.SettingsEnums; import android.content.Context; import android.os.Bundle; import android.provider.SearchIndexableResource; +import androidx.preference.Preference; + import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; @@ -34,14 +39,28 @@ import java.util.List; public class AdaptiveSleepSettings extends DashboardFragment { private static final String TAG = "AdaptiveSleepSettings"; + private Context mContext; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); final FooterPreference footerPreference = mFooterPreferenceMixin.createFooterPreference(); + mContext = getContext(); + footerPreference.setIcon(R.drawable.ic_privacy_shield_24dp); footerPreference.setTitle(R.string.adaptive_sleep_privacy); + + Preference permissionPreference = findPreference( + AdaptiveSleepPermissionPreferenceController.PREF_NAME); + if (permissionPreference != null) { + permissionPreference.setVisible(false); + } + + mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE) + .edit() + .putBoolean(PREF_KEY_INTERACTED, true) + .apply(); } @Override diff --git a/src/com/android/settings/display/ColorModePreferenceFragment.java b/src/com/android/settings/display/ColorModePreferenceFragment.java index c28de731ffe..598d9c16bd0 100644 --- a/src/com/android/settings/display/ColorModePreferenceFragment.java +++ b/src/com/android/settings/display/ColorModePreferenceFragment.java @@ -213,5 +213,13 @@ public class ColorModePreferenceFragment extends RadioButtonPickerFragment { sir.xmlResId = R.xml.color_mode_settings; return Arrays.asList(sir); } + + @Override + protected boolean isPageSearchEnabled(Context context) { + final int[] availableColorModes = context.getResources().getIntArray( + com.android.internal.R.array.config_availableColorModes); + return availableColorModes != null && availableColorModes.length > 0 + && !ColorDisplayManager.areAccessibilityTransformsEnabled(context); + } }; } diff --git a/src/com/android/settings/gestures/GestureNavigationNotAvailableDialog.java b/src/com/android/settings/gestures/GestureNavigationNotAvailableDialog.java deleted file mode 100644 index 6e8b4142d8b..00000000000 --- a/src/com/android/settings/gestures/GestureNavigationNotAvailableDialog.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2019 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.gestures; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.settings.SettingsEnums; -import android.content.Context; -import android.os.Bundle; - -import com.android.settings.R; -import com.android.settings.core.instrumentation.InstrumentedDialogFragment; - -/** - * Dialog to notify user that gesture navigation is not available because of unsupported launcher. - */ -public class GestureNavigationNotAvailableDialog extends InstrumentedDialogFragment { - private static final String TAG = "GestureNavigationNotAvailableDialog"; - - public static void show(SystemNavigationGestureSettings parent) { - if (!parent.isAdded()) { - return; - } - - final GestureNavigationNotAvailableDialog dialog = - new GestureNavigationNotAvailableDialog(); - dialog.setTargetFragment(parent, 0); - dialog.show(parent.getFragmentManager(), TAG); - } - - @Override - public int getMetricsCategory() { - return SettingsEnums.SETTINGS_GESTURE_NAV_NOT_AVAILABLE_DLG; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Context context = getActivity(); - final String defaultHomeAppName = SystemNavigationPreferenceController - .getDefaultHomeAppName(context); - final String message = getString(R.string.gesture_not_supported_dialog_message, - defaultHomeAppName); - return new AlertDialog.Builder(context) - .setMessage(message) - .setPositiveButton(R.string.okay, null) - .create(); - } -} \ No newline at end of file diff --git a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java index b3d090d75f2..3def7804bb5 100644 --- a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java +++ b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java @@ -22,7 +22,6 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVE import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY; import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_GONE; -import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_INFO; import static com.android.settings.widget.RadioButtonPreferenceWithExtraWidget.EXTRA_WIDGET_VISIBILITY_SETTING; import android.accessibilityservice.AccessibilityServiceInfo; @@ -160,17 +159,9 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment { RadioButtonPreferenceWithExtraWidget p = (RadioButtonPreferenceWithExtraWidget) pref; if (info.getKey() == KEY_SYSTEM_NAV_GESTURAL) { - if (SystemNavigationPreferenceController.isGestureNavSupportedByDefaultLauncher( - getContext())) { - p.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_SETTING); - p.setExtraWidgetOnClickListener((v) -> GestureNavigationBackSensitivityDialog - .show(this, getBackSensitivity(getContext(), mOverlayManager))); - } else { - p.setEnabled(false); - p.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_INFO); - p.setExtraWidgetOnClickListener((v) -> - GestureNavigationNotAvailableDialog.show(this)); - } + p.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_SETTING); + p.setExtraWidgetOnClickListener((v) -> GestureNavigationBackSensitivityDialog + .show(this, getBackSensitivity(getContext(), mOverlayManager))); } else { p.setExtraWidgetVisibility(EXTRA_WIDGET_VISIBILITY_GONE); } @@ -219,12 +210,6 @@ public class SystemNavigationGestureSettings extends RadioButtonPickerFragment { @Override protected boolean setDefaultKey(String key) { final Context c = getContext(); - if (key == KEY_SYSTEM_NAV_GESTURAL && - !SystemNavigationPreferenceController.isGestureNavSupportedByDefaultLauncher(c)) { - // This should not happen since the preference is disabled. Return to be safe. - return false; - } - setCurrentSystemNavigationMode(c, mOverlayManager, key); setIllustrationVideo(mVideoPreference, key); if (TextUtils.equals(KEY_SYSTEM_NAV_GESTURAL, key) && ( diff --git a/src/com/android/settings/gestures/SystemNavigationPreferenceController.java b/src/com/android/settings/gestures/SystemNavigationPreferenceController.java index a151dc1746c..d0d81552ff5 100644 --- a/src/com/android/settings/gestures/SystemNavigationPreferenceController.java +++ b/src/com/android/settings/gestures/SystemNavigationPreferenceController.java @@ -22,14 +22,11 @@ import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; -import java.util.ArrayList; - public class SystemNavigationPreferenceController extends BasePreferenceController { static final String PREF_KEY_SYSTEM_NAVIGATION = "gesture_system_navigation"; @@ -101,31 +98,4 @@ public class SystemNavigationPreferenceController extends BasePreferenceControll return NAV_BAR_MODE_GESTURAL == context.getResources().getInteger( com.android.internal.R.integer.config_navBarInteractionMode); } - - static boolean isGestureNavSupportedByDefaultLauncher(Context context) { - final ComponentName cn = context.getPackageManager().getHomeActivities(new ArrayList<>()); - if (cn == null) { - // There is no default home app set for the current user, don't make any changes yet. - return true; - } - ComponentName recentsComponentName = ComponentName.unflattenFromString(context.getString( - com.android.internal.R.string.config_recentsComponentName)); - return recentsComponentName.getPackageName().equals(cn.getPackageName()); - } - - static String getDefaultHomeAppName(Context context) { - final PackageManager pm = context.getPackageManager(); - final ComponentName cn = pm.getHomeActivities(new ArrayList<>()); - if (cn != null) { - try { - ApplicationInfo ai = pm.getApplicationInfo(cn.getPackageName(), 0); - if (ai != null) { - return pm.getApplicationLabel(ai).toString(); - } - } catch (final PackageManager.NameNotFoundException e) { - // Do nothing - } - } - return ""; - } } diff --git a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java index 86fee03e556..385f8cda010 100644 --- a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java +++ b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java @@ -64,12 +64,28 @@ public class SettingsContextualCardProvider extends ContextualCardProvider { .setCardName(contextualNotificationChannelSliceUri) .setCardCategory(ContextualCard.Category.POSSIBLE) .build(); + final String contextualAdaptiveSleepSliceUri = + CustomSliceRegistry.CONTEXTUAL_ADAPTIVE_SLEEP_URI.toString(); + final ContextualCard contextualAdaptiveSleepCard = + ContextualCard.newBuilder() + .setSliceUri(contextualAdaptiveSleepSliceUri) + .setCardName(contextualAdaptiveSleepSliceUri) + .setCardCategory(ContextualCard.Category.DEFAULT) + .build(); + final ContextualCard contextualFaceSettingsCard = + ContextualCard.newBuilder() + .setSliceUri(CustomSliceRegistry.FACE_ENROLL_SLICE_URI.toString()) + .setCardName(CustomSliceRegistry.FACE_ENROLL_SLICE_URI.toString()) + .setCardCategory(ContextualCard.Category.DEFAULT) + .build(); final ContextualCardList cards = ContextualCardList.newBuilder() .addCard(wifiCard) .addCard(connectedDeviceCard) .addCard(lowStorageCard) .addCard(batteryFixCard) .addCard(notificationChannelCard) + .addCard(contextualAdaptiveSleepCard) + .addCard(contextualFaceSettingsCard) .build(); return cards; diff --git a/src/com/android/settings/homepage/contextualcards/slices/ContextualAdaptiveSleepSlice.java b/src/com/android/settings/homepage/contextualcards/slices/ContextualAdaptiveSleepSlice.java new file mode 100644 index 00000000000..3da57634e58 --- /dev/null +++ b/src/com/android/settings/homepage/contextualcards/slices/ContextualAdaptiveSleepSlice.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2019 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.homepage.contextualcards.slices; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; +import static com.android.settings.display.AdaptiveSleepPreferenceController.PREF_NAME; +import static com.android.settings.display.AdaptiveSleepPreferenceController.isControllerAvailable; +import static com.android.settings.slices.CustomSliceRegistry.CONTEXTUAL_ADAPTIVE_SLEEP_URI; + +import android.app.PendingIntent; +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; + +import androidx.core.graphics.drawable.IconCompat; +import androidx.slice.Slice; +import androidx.slice.builders.ListBuilder; +import androidx.slice.builders.SliceAction; + +import com.android.settings.R; +import com.android.settings.SubSettings; +import com.android.settings.display.AdaptiveSleepSettings; +import com.android.settings.slices.CustomSliceable; +import com.android.settings.slices.SliceBuilderUtils; + +import com.google.common.annotations.VisibleForTesting; + +import java.util.concurrent.TimeUnit; + +public class ContextualAdaptiveSleepSlice implements CustomSliceable { + private static final String TAG = "ContextualAdaptiveSleepSlice"; + private static final long DEFAULT_SETUP_TIME = 0; + private Context mContext; + + @VisibleForTesting + static final long DEFERRED_TIME_DAYS = TimeUnit.DAYS.toMillis(14); + @VisibleForTesting + static final String PREF_KEY_SETUP_TIME = "adaptive_sleep_setup_time"; + + public static final String PREF_KEY_INTERACTED = "adaptive_sleep_interacted"; + public static final String PREF = "adaptive_sleep_slice"; + + public ContextualAdaptiveSleepSlice(Context context) { + mContext = context; + } + + @Override + public Slice getSlice() { + final long setupTime = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE).getLong( + PREF_KEY_SETUP_TIME, DEFAULT_SETUP_TIME); + if (setupTime == DEFAULT_SETUP_TIME) { + // Set the first setup time. + mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE) + .edit() + .putLong(PREF_KEY_SETUP_TIME, System.currentTimeMillis()) + .apply(); + return null; + } + + // Display the contextual card only if all the following 3 conditions hold: + // 1. The Screen Attention is enabled in Settings. + // 2. The device is not recently set up. + // 3. Current user hasn't opened Screen Attention's settings page before. + if (isSettingsAvailable() && !isUserInteracted() && !isRecentlySetup()) { + final IconCompat icon = IconCompat.createWithResource(mContext, + R.drawable.ic_settings_adaptive_sleep); + final CharSequence title = mContext.getText(R.string.adaptive_sleep_title); + final CharSequence subtitle = mContext.getText( + R.string.adaptive_sleep_contextual_slice_summary); + + final SliceAction pAction = SliceAction.createDeeplink(getPrimaryAction(), + icon, + ListBuilder.ICON_IMAGE, + title); + final ListBuilder listBuilder = new ListBuilder(mContext, + CONTEXTUAL_ADAPTIVE_SLEEP_URI, + ListBuilder.INFINITY) + .setAccentColor(COLOR_NOT_TINTED) + .addRow(new ListBuilder.RowBuilder() + .setTitleItem(icon, ListBuilder.ICON_IMAGE) + .setTitle(title) + .setSubtitle(subtitle) + .setPrimaryAction(pAction)); + return listBuilder.build(); + } else { + return null; + } + } + + @Override + public Uri getUri() { + return CONTEXTUAL_ADAPTIVE_SLEEP_URI; + } + + @Override + public Intent getIntent() { + final CharSequence screenTitle = mContext.getText(R.string.adaptive_sleep_title); + final Uri contentUri = new Uri.Builder().appendPath(PREF_NAME).build(); + return SliceBuilderUtils.buildSearchResultPageIntent(mContext, + AdaptiveSleepSettings.class.getName(), PREF_NAME, screenTitle.toString(), + SettingsEnums.SLICE).setClassName(mContext.getPackageName(), + SubSettings.class.getName()).setData(contentUri); + } + + private PendingIntent getPrimaryAction() { + final Intent intent = getIntent(); + return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */); + } + + /** + * @return {@code true} if the current user has opened the Screen Attention settings page + * before, otherwise {@code false}. + */ + private boolean isUserInteracted() { + return mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE).getBoolean( + PREF_KEY_INTERACTED, false); + } + + /** + * The device is recently set up means its first settings-open time is within 2 weeks ago. + * + * @return {@code true} if the device is recently set up, otherwise {@code false}. + */ + private boolean isRecentlySetup() { + final long endTime = System.currentTimeMillis() - DEFERRED_TIME_DAYS; + final long firstSetupTime = mContext.getSharedPreferences(PREF, + Context.MODE_PRIVATE).getLong(PREF_KEY_SETUP_TIME, DEFAULT_SETUP_TIME); + return firstSetupTime > endTime; + } + + /** + * Check whether the screen attention settings is enabled. Contextual card will only appear + * when the screen attention settings is available. + * + * @return {@code true} if screen attention settings is enabled, otherwise {@code false} + */ + @VisibleForTesting + boolean isSettingsAvailable() { + return isControllerAvailable(mContext) == AVAILABLE_UNSEARCHABLE; + } +} \ No newline at end of file diff --git a/src/com/android/settings/homepage/contextualcards/slices/FaceSetupSlice.java b/src/com/android/settings/homepage/contextualcards/slices/FaceSetupSlice.java new file mode 100644 index 00000000000..112f6557019 --- /dev/null +++ b/src/com/android/settings/homepage/contextualcards/slices/FaceSetupSlice.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2019 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.homepage.contextualcards.slices; + + +import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_SUCCESS; + +import android.app.PendingIntent; +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.hardware.biometrics.BiometricManager; +import android.hardware.face.FaceManager; +import android.net.Uri; +import android.os.UserHandle; + +import androidx.core.graphics.drawable.IconCompat; +import androidx.slice.Slice; +import androidx.slice.builders.ListBuilder; +import androidx.slice.builders.ListBuilder.RowBuilder; +import androidx.slice.builders.SliceAction; + +import com.android.settings.R; +import com.android.settings.SubSettings; +import com.android.settings.Utils; +import com.android.settings.biometrics.face.FaceStatusPreferenceController; +import com.android.settings.security.SecuritySettings; +import com.android.settings.slices.CustomSliceRegistry; +import com.android.settings.slices.CustomSliceable; +import com.android.settings.slices.SliceBuilderUtils; + +public class FaceSetupSlice implements CustomSliceable { + + private final Context mContext; + + public FaceSetupSlice(Context context) { + mContext = context; + } + + @Override + public Slice getSlice() { + final FaceManager faceManager = Utils.getFaceManagerOrNull(mContext); + if (faceManager == null || faceManager.hasEnrolledTemplates(UserHandle.myUserId())) { + return null; + } + + final CharSequence title = mContext.getText( + R.string.security_settings_face_settings_enroll); + final ListBuilder listBuilder = new ListBuilder(mContext, + CustomSliceRegistry.FACE_ENROLL_SLICE_URI, ListBuilder.INFINITY) + .setAccentColor(Utils.getColorAccentDefaultColor(mContext)); + final IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.ic_face_24dp); + return listBuilder + .addRow(buildRowBuilder(title, + mContext.getText(R.string.security_settings_face_settings_context_subtitle), + icon, mContext, getIntent())) + .build(); + } + + @Override + public Uri getUri() { + return CustomSliceRegistry.FACE_ENROLL_SLICE_URI; + } + + @Override + public Intent getIntent() { + return SliceBuilderUtils.buildSearchResultPageIntent(mContext, + SecuritySettings.class.getName(), + FaceStatusPreferenceController.KEY_FACE_SETTINGS, + mContext.getText(R.string.security_settings_face_settings_enroll).toString(), + SettingsEnums.SLICE) + .setClassName(mContext.getPackageName(), SubSettings.class.getName()); + } + + private static RowBuilder buildRowBuilder(CharSequence title, CharSequence subTitle, + IconCompat icon, Context context, Intent intent) { + final SliceAction primarySliceAction = SliceAction.createDeeplink( + PendingIntent.getActivity(context, 0, intent, 0), icon, ListBuilder.ICON_IMAGE, + title); + return new RowBuilder() + .setTitleItem(icon, ListBuilder.ICON_IMAGE) + .setTitle(title) + .setSubtitle(subTitle) + .setPrimaryAction(primarySliceAction); + } +} \ No newline at end of file diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.java b/src/com/android/settings/network/MobileNetworkSummaryController.java index 0f76f24de56..bd3e2efbb6d 100644 --- a/src/com/android/settings/network/MobileNetworkSummaryController.java +++ b/src/com/android/settings/network/MobileNetworkSummaryController.java @@ -130,7 +130,7 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController } private void update() { - if (mPreference == null) { + if (mPreference == null || mPreference.isDisabledByAdmin()) { return; } refreshSummary(mPreference); diff --git a/src/com/android/settings/network/TetherProvisioningActivity.java b/src/com/android/settings/network/TetherProvisioningActivity.java index 48c570791b2..53a86cb39a6 100644 --- a/src/com/android/settings/network/TetherProvisioningActivity.java +++ b/src/com/android/settings/network/TetherProvisioningActivity.java @@ -55,7 +55,7 @@ public class TetherProvisioningActivity extends Activity { final int tetherSubId = getIntent().getIntExtra(EXTRA_SUBID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); - final int subId = SubscriptionManager.getDefaultDataSubscriptionId(); + final int subId = SubscriptionManager.getActiveDataSubscriptionId(); if (tetherSubId != subId) { Log.e(TAG, "This Provisioning request is outdated, current subId: " + subId); return; @@ -67,6 +67,7 @@ public class TetherProvisioningActivity extends Activity { final Intent intent = new Intent(Intent.ACTION_MAIN); intent.setClassName(provisionApp[0], provisionApp[1]); intent.putExtra(EXTRA_TETHER_TYPE, tetherType); + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); if (DEBUG) { Log.d(TAG, "Starting provisioning app: " + provisionApp[0] + "." + provisionApp[1]); } diff --git a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java index 94b176107c2..79cdc2e6b60 100644 --- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java +++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java @@ -16,7 +16,13 @@ package com.android.settings.network.telephony; +import static androidx.lifecycle.Lifecycle.Event.ON_START; +import static androidx.lifecycle.Lifecycle.Event.ON_STOP; + import android.content.Context; +import android.database.ContentObserver; +import android.os.Handler; +import android.os.Looper; import android.os.PersistableBundle; import android.provider.Settings; import android.telephony.CarrierConfigManager; @@ -25,8 +31,12 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import androidx.annotation.VisibleForTesting; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; import androidx.preference.ListPreference; import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; @@ -37,17 +47,27 @@ import com.android.settings.R; */ public class EnabledNetworkModePreferenceController extends TelephonyBasePreferenceController implements - ListPreference.OnPreferenceChangeListener { + ListPreference.OnPreferenceChangeListener, LifecycleObserver { private CarrierConfigManager mCarrierConfigManager; + private ContentObserver mPreferredNetworkModeObserver; private TelephonyManager mTelephonyManager; private boolean mIsGlobalCdma; @VisibleForTesting boolean mShow4GForLTE; + private Preference mPreference; public EnabledNetworkModePreferenceController(Context context, String key) { super(context, key); mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); + mPreferredNetworkModeObserver = new ContentObserver(new Handler(Looper.getMainLooper())) { + @Override + public void onChange(boolean selfChange) { + if (mPreference != null) { + updateState(mPreference); + } + } + }; } @Override @@ -78,6 +98,24 @@ public class EnabledNetworkModePreferenceController extends return visible ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } + @OnLifecycleEvent(ON_START) + public void onStart() { + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.PREFERRED_NETWORK_MODE + mSubId), true, + mPreferredNetworkModeObserver); + } + + @OnLifecycleEvent(ON_STOP) + public void onStop() { + mContext.getContentResolver().unregisterContentObserver(mPreferredNetworkModeObserver); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + } + @Override public void updateState(Preference preference) { super.updateState(preference); @@ -102,7 +140,7 @@ public class EnabledNetworkModePreferenceController extends return false; } - public void init(int subId) { + public void init(Lifecycle lifecycle, int subId) { mSubId = subId; final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId); mTelephonyManager = TelephonyManager.from(mContext).createForSubscriptionId(mSubId); @@ -115,6 +153,7 @@ public class EnabledNetworkModePreferenceController extends ? carrierConfig.getBoolean( CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL) : false; + lifecycle.addObserver(this); } private int getPreferredNetworkMode() { diff --git a/src/com/android/settings/network/telephony/MobileNetworkActivity.java b/src/com/android/settings/network/telephony/MobileNetworkActivity.java index b8ed31f94b8..9912b4e9b61 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkActivity.java +++ b/src/com/android/settings/network/telephony/MobileNetworkActivity.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.provider.Settings; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.view.Menu; @@ -76,6 +77,13 @@ public class MobileNetworkActivity extends SettingsBaseActivity { } }; + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + setIntent(intent); + updateSubscriptions(null); + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -86,13 +94,18 @@ public class MobileNetworkActivity extends SettingsBaseActivity { setContentView(R.layout.mobile_network_settings_container); } setActionBar(findViewById(R.id.mobile_action_bar)); - mPhoneChangeReceiver = new PhoneChangeReceiver(this, () -> { - if (mCurSubscriptionId != SUB_ID_NULL) { - // When the radio changes (ex: CDMA->GSM), refresh the fragment. - // This is very rare. + mPhoneChangeReceiver = new PhoneChangeReceiver(this, new PhoneChangeReceiver.Client() { + @Override + public void onPhoneChange() { + // When the radio or carrier config changes (ex: CDMA->GSM), refresh the fragment. switchFragment(new MobileNetworkSettings(), mCurSubscriptionId, true /* forceUpdate */); } + + @Override + public int getSubscriptionId() { + return mCurSubscriptionId; + } }); mSubscriptionManager = getSystemService(SubscriptionManager.class); mSubscriptionInfos = mSubscriptionManager.getActiveSubscriptionInfoList(true); @@ -243,14 +256,12 @@ public class MobileNetworkActivity extends SettingsBaseActivity { @VisibleForTesting static class PhoneChangeReceiver extends BroadcastReceiver { - private static final IntentFilter RADIO_TECHNOLOGY_CHANGED_FILTER = new IntentFilter( - TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); - private Context mContext; private Client mClient; interface Client { void onPhoneChange(); + int getSubscriptionId(); } public PhoneChangeReceiver(Context context, Client client) { @@ -259,7 +270,10 @@ public class MobileNetworkActivity extends SettingsBaseActivity { } public void register() { - mContext.registerReceiver(this, RADIO_TECHNOLOGY_CHANGED_FILTER); + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); + intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + mContext.registerReceiver(this, intentFilter); } public void unregister() { @@ -268,9 +282,17 @@ public class MobileNetworkActivity extends SettingsBaseActivity { @Override public void onReceive(Context context, Intent intent) { - if (!isInitialStickyBroadcast()) { - mClient.onPhoneChange(); + if (isInitialStickyBroadcast()) { + return; } + if (intent.getAction().equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) { + if (!intent.hasExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX) || + intent.getIntExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, -1) + != mClient.getSubscriptionId()) { + return; + } + } + mClient.onPhoneChange(); } } } diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index c8e2247db15..8d83ef2a3f9 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -150,7 +150,7 @@ public class MobileNetworkSettings extends RestrictedDashboardFragment { use(CarrierPreferenceController.class).init(mSubId); use(DataUsagePreferenceController.class).init(mSubId); use(PreferredNetworkModePreferenceController.class).init(mSubId); - use(EnabledNetworkModePreferenceController.class).init(mSubId); + use(EnabledNetworkModePreferenceController.class).init(getLifecycle(), mSubId); use(DataServiceSetupPreferenceController.class).init(mSubId); if (!FeatureFlagPersistent.isEnabled(getContext(), FeatureFlags.NETWORK_INTERNET_V2)) { use(EuiccPreferenceController.class).init(mSubId); diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java index 4d4d3ef7f01..59984837224 100644 --- a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java +++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java @@ -61,16 +61,12 @@ public class WifiCallingPreferenceController extends TelephonyBasePreferenceCont PhoneAccountHandle mSimCallManager; private PhoneCallStateListener mPhoneStateListener; private Preference mPreference; - private boolean mEditableWfcRoamingMode; - private boolean mUseWfcHomeModeForRoaming; public WifiCallingPreferenceController(Context context, String key) { super(context, key); mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); mTelephonyManager = context.getSystemService(TelephonyManager.class); mPhoneStateListener = new PhoneCallStateListener(Looper.getMainLooper()); - mEditableWfcRoamingMode = true; - mUseWfcHomeModeForRoaming = false; } @Override @@ -129,9 +125,18 @@ public class WifiCallingPreferenceController extends TelephonyBasePreferenceCont preference.setTitle(title); int resId = com.android.internal.R.string.wifi_calling_off_summary; if (mImsManager.isWfcEnabledByUser()) { - boolean wfcRoamingEnabled = mEditableWfcRoamingMode && !mUseWfcHomeModeForRoaming; + boolean useWfcHomeModeForRoaming = false; + if (mCarrierConfigManager != null) { + final PersistableBundle carrierConfig = + mCarrierConfigManager.getConfigForSubId(mSubId); + if (carrierConfig != null) { + useWfcHomeModeForRoaming = carrierConfig.getBoolean( + CarrierConfigManager + .KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL); + } + } final boolean isRoaming = mTelephonyManager.isNetworkRoaming(); - int wfcMode = mImsManager.getWfcMode(isRoaming && wfcRoamingEnabled); + int wfcMode = mImsManager.getWfcMode(isRoaming && !useWfcHomeModeForRoaming); switch (wfcMode) { case ImsConfig.WfcModeFeatureValueConstants.WIFI_ONLY: resId = com.android.internal.R.string.wfc_mode_wifi_only_summary; @@ -159,16 +164,6 @@ public class WifiCallingPreferenceController extends TelephonyBasePreferenceCont mImsManager = ImsManager.getInstance(mContext, SubscriptionManager.getPhoneId(mSubId)); mSimCallManager = mContext.getSystemService(TelecomManager.class) .getSimCallManagerForSubscription(mSubId); - if (mCarrierConfigManager != null) { - final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId); - if (carrierConfig != null) { - mEditableWfcRoamingMode = carrierConfig.getBoolean( - CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL); - mUseWfcHomeModeForRoaming = carrierConfig.getBoolean( - CarrierConfigManager - .KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL); - } - } } private class PhoneCallStateListener extends PhoneStateListener { diff --git a/src/com/android/settings/notification/RingtonePreferenceControllerBase.java b/src/com/android/settings/notification/RingtonePreferenceControllerBase.java index 733d0d937d7..c82afb4d1f6 100644 --- a/src/com/android/settings/notification/RingtonePreferenceControllerBase.java +++ b/src/com/android/settings/notification/RingtonePreferenceControllerBase.java @@ -55,7 +55,7 @@ public abstract class RingtonePreferenceControllerBase extends AbstractPreferenc final CharSequence summary; if (ringtoneUri == null) { - summary = null; + summary = mContext.getString(com.android.internal.R.string.ringtone_silent); } else { summary = Ringtone.getTitle( mContext, ringtoneUri, false /* followSettingsUri */, true /* allowRemote */); diff --git a/src/com/android/settings/password/ChooseLockSettingsHelper.java b/src/com/android/settings/password/ChooseLockSettingsHelper.java index 28ded2d8bf9..3353d62053f 100644 --- a/src/com/android/settings/password/ChooseLockSettingsHelper.java +++ b/src/com/android/settings/password/ChooseLockSettingsHelper.java @@ -47,6 +47,7 @@ public final class ChooseLockSettingsHelper { public static final String EXTRA_KEY_FOR_FINGERPRINT = "for_fingerprint"; public static final String EXTRA_KEY_FOR_FACE = "for_face"; 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"; /** * Intent extra for passing the requested min password complexity to later steps in the set new @@ -105,7 +106,8 @@ public final class ChooseLockSettingsHelper { null /* header */, null /* description */, false /* returnCredentials */, - false /* external */); + false /* external */, + false /* foregroundOnly */); } /** @@ -124,7 +126,8 @@ public final class ChooseLockSettingsHelper { null /* header */, null /* description */, returnCredentials /* returnCredentials */, - false /* external */); + false /* external */, + false /* foregroundOnly */); } /** @@ -148,7 +151,8 @@ public final class ChooseLockSettingsHelper { false /* external */, false /* hasChallenge */, 0 /* challenge */, - Utils.enforceSameOwner(mActivity, userId) /* userId */); + Utils.enforceSameOwner(mActivity, userId) /* userId */, + false /* foregroundOnly */); } /** @@ -162,12 +166,13 @@ public final class ChooseLockSettingsHelper { * @param external specifies whether this activity is launched externally, meaning that it will * get a dark theme, allow fingerprint authentication and it will forward * activity result. + * @param foregroundOnly if the confirmation activity should be finished if it loses foreground. * @return true if one exists and we launched an activity to confirm it * @see Activity#onActivityResult(int, int, android.content.Intent) */ boolean launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, - boolean returnCredentials, boolean external) { + boolean returnCredentials, boolean external, boolean foregroundOnly) { return launchConfirmationActivity( request /* request */, title /* title */, @@ -177,7 +182,8 @@ public final class ChooseLockSettingsHelper { external /* external */, false /* hasChallenge */, 0 /* challenge */, - Utils.getCredentialOwnerUserId(mActivity) /* userId */); + Utils.getCredentialOwnerUserId(mActivity) /* userId */, + foregroundOnly /* foregroundOnly */); } /** @@ -207,7 +213,8 @@ public final class ChooseLockSettingsHelper { external /* external */, false /* hasChallenge */, 0 /* challenge */, - Utils.enforceSameOwner(mActivity, userId) /* userId */); + Utils.enforceSameOwner(mActivity, userId) /* userId */, + false /* foregroundOnly */); } /** @@ -217,12 +224,13 @@ public final class ChooseLockSettingsHelper { * @param header header of the confirmation screen; shown as large text * @param description description of the confirmation screen * @param challenge a challenge to be verified against the device credential. + * @param foregroundOnly if the confirmation activity should be finished if it loses foreground. * @return true if one exists and we launched an activity to confirm it * @see Activity#onActivityResult(int, int, android.content.Intent) */ public boolean launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, - long challenge) { + long challenge, boolean foregroundOnly) { return launchConfirmationActivity( request /* request */, title /* title */, @@ -232,7 +240,8 @@ public final class ChooseLockSettingsHelper { false /* external */, true /* hasChallenge */, challenge /* challenge */, - Utils.getCredentialOwnerUserId(mActivity) /* userId */); + Utils.getCredentialOwnerUserId(mActivity) /* userId */, + foregroundOnly /* foregroundOnly */); } /** @@ -243,12 +252,13 @@ public final class ChooseLockSettingsHelper { * @param description description of the confirmation screen * @param challenge a challenge to be verified against the device credential. * @param userId The userId for whom the lock should be confirmed. + * @param foregroundOnly if the confirmation activity should be finished if it loses foreground. * @return true if one exists and we launched an activity to confirm it * @see Activity#onActivityResult(int, int, android.content.Intent) */ public boolean launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, - long challenge, int userId) { + long challenge, int userId, boolean foregroundOnly) { return launchConfirmationActivity( request /* request */, title /* title */, @@ -258,7 +268,8 @@ public final class ChooseLockSettingsHelper { false /* external */, true /* hasChallenge */, challenge /* challenge */, - Utils.enforceSameOwner(mActivity, userId) /* userId */); + Utils.enforceSameOwner(mActivity, userId) /* userId */, + foregroundOnly); } /** @@ -287,7 +298,8 @@ public final class ChooseLockSettingsHelper { external /* external */, true /* hasChallenge */, challenge /* challenge */, - Utils.enforceSameOwner(mActivity, userId) /* userId */); + Utils.enforceSameOwner(mActivity, userId) /* userId */, + false /* foregroundOnly */); } /** @@ -316,7 +328,7 @@ public final class ChooseLockSettingsHelper { private boolean launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean hasChallenge, - long challenge, int userId) { + long challenge, int userId, boolean foregroundOnly) { return launchConfirmationActivity( request /* request */, title /* title */, @@ -328,7 +340,8 @@ public final class ChooseLockSettingsHelper { challenge /* challenge */, userId /* userId */, null /* alternateButton */, - null /* extras */); + null /* extras */, + foregroundOnly /* foregroundOnly */); } private boolean launchConfirmationActivity(int request, @Nullable CharSequence title, @@ -346,7 +359,8 @@ public final class ChooseLockSettingsHelper { challenge /* challenge */, userId /* userId */, null /* alternateButton */, - extras /* extras */); + extras /* extras */, + false /* foregroundOnly */); } public boolean launchFrpConfirmationActivity(int request, @Nullable CharSequence header, @@ -362,13 +376,15 @@ public final class ChooseLockSettingsHelper { 0 /* challenge */, LockPatternUtils.USER_FRP /* userId */, alternateButton /* alternateButton */, - null /* extras */); + null /* extras */, + false /* foregroundOnly */); } private boolean launchConfirmationActivity(int request, @Nullable CharSequence title, @Nullable CharSequence header, @Nullable CharSequence description, boolean returnCredentials, boolean external, boolean hasChallenge, - long challenge, int userId, @Nullable CharSequence alternateButton, Bundle extras) { + long challenge, int userId, @Nullable CharSequence alternateButton, Bundle extras, + boolean foregroundOnly) { final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId); boolean launched = false; @@ -378,7 +394,8 @@ public final class ChooseLockSettingsHelper { returnCredentials || hasChallenge ? ConfirmLockPattern.InternalActivity.class : ConfirmLockPattern.class, returnCredentials, external, - hasChallenge, challenge, userId, alternateButton, extras); + hasChallenge, challenge, userId, alternateButton, extras, + foregroundOnly); break; case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC: case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX: @@ -390,7 +407,8 @@ public final class ChooseLockSettingsHelper { returnCredentials || hasChallenge ? ConfirmLockPassword.InternalActivity.class : ConfirmLockPassword.class, returnCredentials, external, - hasChallenge, challenge, userId, alternateButton, extras); + hasChallenge, challenge, userId, alternateButton, extras, + foregroundOnly); break; } return launched; @@ -399,7 +417,8 @@ public final class ChooseLockSettingsHelper { private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header, CharSequence message, Class activityClass, boolean returnCredentials, boolean external, boolean hasChallenge, long challenge, - int userId, @Nullable CharSequence alternateButton, Bundle extras) { + int userId, @Nullable CharSequence alternateButton, Bundle extras, + boolean foregroundOnly) { final Intent intent = new Intent(); intent.putExtra(ConfirmDeviceCredentialBaseFragment.TITLE_TEXT, title); intent.putExtra(ConfirmDeviceCredentialBaseFragment.HEADER_TEXT, header); @@ -414,6 +433,7 @@ public final class ChooseLockSettingsHelper { intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge); intent.putExtra(Intent.EXTRA_USER_ID, userId); intent.putExtra(KeyguardManager.EXTRA_ALTERNATE_BUTTON_LABEL, alternateButton); + intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOREGROUND_ONLY, foregroundOnly); if (extras != null) { intent.putExtras(extras); } diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java index 998b3fcdd18..5407776f3b1 100644 --- a/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java +++ b/src/com/android/settings/password/ConfirmDeviceCredentialBaseActivity.java @@ -172,6 +172,10 @@ public abstract class ConfirmDeviceCredentialBaseActivity extends SettingsActivi mBiometricManager.onConfirmDeviceCredentialError( BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED, getString(com.android.internal.R.string.biometric_error_user_canceled)); + if (getIntent().getBooleanExtra( + ChooseLockSettingsHelper.EXTRA_KEY_FOREGROUND_ONLY, false)) { + finish(); + } } } diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java index 9a165297942..aa17f8e987f 100644 --- a/src/com/android/settings/password/SetupChooseLockGeneric.java +++ b/src/com/android/settings/password/SetupChooseLockGeneric.java @@ -111,7 +111,7 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric { layout.setIcon(getContext().getDrawable(R.drawable.ic_lock)); - int titleResource = mForFingerprint ? + int titleResource = isForBiometric() ? R.string.lock_settings_picker_title : R.string.setup_lock_settings_picker_title; if (getActivity() != null) { getActivity().setTitle(titleResource); @@ -125,7 +125,7 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric { @Override protected void addHeaderView() { - if (mForFingerprint || mForFace) { + if (isForBiometric()) { setHeaderView(R.layout.setup_choose_lock_generic_biometrics_header); } else { setHeaderView(R.layout.setup_choose_lock_generic_header); @@ -183,7 +183,7 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric { @Override protected void addPreferences() { - if (mForFingerprint) { + if (isForBiometric()) { super.addPreferences(); } else { addPreferencesFromResource(R.xml.setup_security_settings_picker); @@ -240,6 +240,10 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric { SetupWizardUtils.copySetupExtras(getActivity().getIntent(), intent); return intent; } + + private boolean isForBiometric() { + return mForFingerprint || mForFace; + } } public static class InternalActivity extends ChooseLockGeneric.InternalActivity { @@ -261,5 +265,4 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric { } } } - } diff --git a/src/com/android/settings/privacy/EnableContentCaptureWithServiceSettingsPreferenceController.java b/src/com/android/settings/privacy/EnableContentCaptureWithServiceSettingsPreferenceController.java index 809bfbdc21f..77aab34c9c3 100644 --- a/src/com/android/settings/privacy/EnableContentCaptureWithServiceSettingsPreferenceController.java +++ b/src/com/android/settings/privacy/EnableContentCaptureWithServiceSettingsPreferenceController.java @@ -96,18 +96,23 @@ public final class EnableContentCaptureWithServiceSettingsPreferenceController for (UserInfo info: userInfos) { userHandles.add(info.getUserHandle()); } - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - UserAdapter adapter = UserAdapter.createUserAdapter(userManager, context, userHandles); - builder.setTitle(com.android.settingslib.R.string.choose_profile) - .setAdapter(adapter, (DialogInterface dialog, int which) -> { - final UserHandle user = userHandles.get(which); - // Show menu on top level items. - final Intent intent = pref.getIntent(); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); - context.startActivityAsUser(intent, user); - }) - .show(); + if (userHandles.size() == 1) { + final Intent intent = pref.getIntent().addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + context.startActivityAsUser(intent, userHandles.get(0)); + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + UserAdapter adapter = UserAdapter.createUserAdapter(userManager, context, + userHandles); + builder.setTitle(com.android.settingslib.R.string.choose_profile) + .setAdapter(adapter, (DialogInterface dialog, int which) -> { + final UserHandle user = userHandles.get(which); + // Show menu on top level items. + final Intent intent = pref.getIntent() + .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + context.startActivityAsUser(intent, user); + }) + .show(); + } } } diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java index dc3324b3d92..946a9d3dfda 100644 --- a/src/com/android/settings/slices/CustomSliceRegistry.java +++ b/src/com/android/settings/slices/CustomSliceRegistry.java @@ -26,6 +26,7 @@ import android.util.ArrayMap; import androidx.annotation.VisibleForTesting; +import com.android.settings.display.AdaptiveSleepPreferenceController; import com.android.settings.flashlight.FlashlightSlice; import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController; import com.android.settings.homepage.contextualcards.deviceinfo.DataUsageSlice; @@ -34,7 +35,9 @@ import com.android.settings.homepage.contextualcards.deviceinfo.EmergencyInfoSli import com.android.settings.homepage.contextualcards.deviceinfo.StorageSlice; import com.android.settings.homepage.contextualcards.slices.BatteryFixSlice; import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlice; +import com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice; import com.android.settings.homepage.contextualcards.slices.ContextualNotificationChannelSlice; +import com.android.settings.homepage.contextualcards.slices.FaceSetupSlice; import com.android.settings.homepage.contextualcards.slices.LowStorageSlice; import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice; import com.android.settings.location.LocationSlice; @@ -64,6 +67,16 @@ public class CustomSliceRegistry { .appendPath(SettingsSlicesContract.KEY_AIRPLANE_MODE) .build(); + /** + * Uri for Contextual Adaptive Sleep Slice + */ + public static final Uri CONTEXTUAL_ADAPTIVE_SLEEP_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSliceProvider.SLICE_AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_INTENT) + .appendPath(AdaptiveSleepPreferenceController.PREF_NAME) + .build(); + /** * Uri for Battery Fix Slice. */ @@ -150,6 +163,15 @@ public class CustomSliceRegistry { .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) .appendPath("enhanced_4g_lte") .build(); + /** + * Slice Uri for Face Enrollment + */ + public static final Uri FACE_ENROLL_SLICE_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSliceProvider.SLICE_AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_ACTION) + .appendPath("face_unlock_greeting_card") + .build(); /** * Backing Uri for the Flashlight Slice. */ @@ -328,21 +350,23 @@ public class CustomSliceRegistry { sUriToSlice.put(BATTERY_FIX_SLICE_URI, BatteryFixSlice.class); sUriToSlice.put(BLUETOOTH_DEVICES_SLICE_URI, BluetoothDevicesSlice.class); + sUriToSlice.put(CONTEXTUAL_ADAPTIVE_SLEEP_URI, ContextualAdaptiveSleepSlice.class); sUriToSlice.put(CONTEXTUAL_NOTIFICATION_CHANNEL_SLICE_URI, ContextualNotificationChannelSlice.class); sUriToSlice.put(CONTEXTUAL_WIFI_SLICE_URI, ContextualWifiSlice.class); sUriToSlice.put(DATA_USAGE_SLICE_URI, DataUsageSlice.class); sUriToSlice.put(DEVICE_INFO_SLICE_URI, DeviceInfoSlice.class); sUriToSlice.put(EMERGENCY_INFO_SLICE_URI, EmergencyInfoSlice.class); + sUriToSlice.put(FACE_ENROLL_SLICE_URI, FaceSetupSlice.class); sUriToSlice.put(FLASHLIGHT_SLICE_URI, FlashlightSlice.class); sUriToSlice.put(LOCATION_SLICE_URI, LocationSlice.class); sUriToSlice.put(LOW_STORAGE_SLICE_URI, LowStorageSlice.class); + sUriToSlice.put(MEDIA_OUTPUT_INDICATOR_SLICE_URI, MediaOutputIndicatorSlice.class); + sUriToSlice.put(MEDIA_OUTPUT_SLICE_URI, MediaOutputSlice.class); sUriToSlice.put(MOBILE_DATA_SLICE_URI, MobileDataSlice.class); sUriToSlice.put(NOTIFICATION_CHANNEL_SLICE_URI, NotificationChannelSlice.class); sUriToSlice.put(STORAGE_SLICE_URI, StorageSlice.class); sUriToSlice.put(WIFI_SLICE_URI, WifiSlice.class); - sUriToSlice.put(MEDIA_OUTPUT_SLICE_URI, MediaOutputSlice.class); - sUriToSlice.put(MEDIA_OUTPUT_INDICATOR_SLICE_URI, MediaOutputIndicatorSlice.class); } public static Class getSliceClassByUri(Uri uri) { diff --git a/src/com/android/settings/wifi/CellularFallbackPreferenceController.java b/src/com/android/settings/wifi/CellularFallbackPreferenceController.java index cbb8fb8e26a..01677891bb1 100644 --- a/src/com/android/settings/wifi/CellularFallbackPreferenceController.java +++ b/src/com/android/settings/wifi/CellularFallbackPreferenceController.java @@ -17,8 +17,11 @@ package com.android.settings.wifi; import android.content.Context; +import android.content.res.Resources; import android.provider.Settings; +import android.telephony.SubscriptionManager; +import com.android.internal.annotations.VisibleForTesting; import com.android.settings.core.TogglePreferenceController; /** @@ -33,7 +36,7 @@ public class CellularFallbackPreferenceController extends TogglePreferenceContro @Override public int getAvailabilityStatus() { - return !avoidBadWifiConfig() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + return avoidBadWifiConfig() ? UNSUPPORTED_ON_DEVICE : AVAILABLE; } @Override @@ -49,12 +52,28 @@ public class CellularFallbackPreferenceController extends TogglePreferenceContro } private boolean avoidBadWifiConfig() { - return mContext.getResources().getInteger( - com.android.internal.R.integer.config_networkAvoidBadWifi) == 1; + final int activeDataSubscriptionId = getActiveDataSubscriptionId(); + if (activeDataSubscriptionId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + return true; + } + + final Resources resources = getResourcesForSubId(activeDataSubscriptionId); + return resources.getInteger(com.android.internal.R.integer.config_networkAvoidBadWifi) == 1; + } + + @VisibleForTesting + int getActiveDataSubscriptionId() { + return SubscriptionManager.getActiveDataSubscriptionId(); + } + + @VisibleForTesting + Resources getResourcesForSubId(int subscriptionId) { + return SubscriptionManager.getResourcesForSubId(mContext, subscriptionId, + false /* useRootLocale */); } private boolean avoidBadWifiCurrentSettings() { return "1".equals(Settings.Global.getString(mContext.getContentResolver(), Settings.Global.NETWORK_AVOID_BAD_WIFI)); } -} \ No newline at end of file +} diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java index 5e49b2e7498..a915766bbe6 100644 --- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java +++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java @@ -682,7 +682,11 @@ public class WifiDetailPreferenceController extends AbstractPreferenceController } mMacAddressPref.setVisible(true); - mMacAddressPref.setSummary(macAddress); + if (macAddress.equals(WifiInfo.DEFAULT_MAC_ADDRESS)) { + mMacAddressPref.setSummary(R.string.device_info_not_available); + } else { + mMacAddressPref.setSummary(macAddress); + } } private String getMacAddress() { diff --git a/src/com/android/settings/wifi/tether/TetherService.java b/src/com/android/settings/wifi/tether/TetherService.java index 34daccf6aea..058bba788ec 100644 --- a/src/com/android/settings/wifi/tether/TetherService.java +++ b/src/com/android/settings/wifi/tether/TetherService.java @@ -85,7 +85,7 @@ public class TetherService extends Service { public void onCreate() { super.onCreate(); if (DEBUG) Log.d(TAG, "Creating TetherService"); - String provisionResponse = getResourceForDefaultDataSubId().getString( + String provisionResponse = getResourceForActiveDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_response); registerReceiver(mReceiver, new IntentFilter(provisionResponse), android.Manifest.permission.CONNECTIVITY_INTERNAL, null); @@ -105,7 +105,7 @@ public class TetherService extends Service { if (intent.hasExtra(EXTRA_SUBID)) { final int tetherSubId = intent.getIntExtra(EXTRA_SUBID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); - final int subId = getTetherServiceWrapper().getDefaultDataSubscriptionId(); + final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); if (tetherSubId != subId) { Log.e(TAG, "This Provisioning request is outdated, current subId: " + subId); if (!mInProvisionCheck) { @@ -273,11 +273,13 @@ public class TetherService extends Service { } private Intent getProvisionBroadcastIntent(int index) { - String provisionAction = getResourceForDefaultDataSubId().getString( + String provisionAction = getResourceForActiveDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui); + final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); Intent intent = new Intent(provisionAction); int type = mCurrentTethers.get(index); intent.putExtra(TETHER_CHOICE, type); + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId); intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); @@ -309,7 +311,7 @@ public class TetherService extends Service { PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0); AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE); - int period = getResourceForDefaultDataSubId().getInteger( + int period = getResourceForActiveDataSubId().getInteger( com.android.internal.R.integer.config_mobile_hotspot_provision_check_period); long periodMs = period * MS_PER_HOUR; long firstTime = SystemClock.elapsedRealtime() + periodMs; @@ -362,7 +364,7 @@ public class TetherService extends Service { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) Log.d(TAG, "Got provision result " + intent); - String provisionResponse = getResourceForDefaultDataSubId().getString( + String provisionResponse = getResourceForActiveDataSubId().getString( com.android.internal.R.string.config_mobile_hotspot_provision_response); if (provisionResponse.equals(intent.getAction())) { @@ -429,14 +431,14 @@ public class TetherService extends Service { mUsageStatsManager.setAppInactive(packageName, isInactive); } - int getDefaultDataSubscriptionId() { - return SubscriptionManager.getDefaultDataSubscriptionId(); + int getActiveDataSubscriptionId() { + return SubscriptionManager.getActiveDataSubscriptionId(); } } @VisibleForTesting - Resources getResourceForDefaultDataSubId() { - final int subId = getTetherServiceWrapper().getDefaultDataSubscriptionId(); + Resources getResourceForActiveDataSubId() { + final int subId = getTetherServiceWrapper().getActiveDataSubscriptionId(); return Utils.getResourcesForSubId(this, subId); } } diff --git a/tests/robotests/res/values/overlayable_icons_test.xml b/tests/robotests/res/values/overlayable_icons_test.xml index bf87f3bb7a7..0dab9cf4ac5 100644 --- a/tests/robotests/res/values/overlayable_icons_test.xml +++ b/tests/robotests/res/values/overlayable_icons_test.xml @@ -26,8 +26,6 @@ @drawable/ic_arrow_back @drawable/ic_arrow_down_24dp @drawable/ic_battery_charging_full - @drawable/ic_battery_saver_accent_24dp - @drawable/ic_battery_status_bad_24dp @drawable/ic_battery_status_good_24dp @drawable/ic_battery_status_maybe_24dp @drawable/ic_call_24dp @@ -38,13 +36,13 @@ @drawable/ic_content_copy_grey600_24dp @drawable/ic_data_saver @drawable/ic_delete - @drawable/ic_delete_accent @drawable/ic_devices_other @drawable/ic_devices_other_opaque_black @drawable/ic_do_not_disturb_on_24dp @drawable/ic_eject_24dp @drawable/ic_expand_less @drawable/ic_expand_more_inverse + @drawable/ic_find_in_page_24px @drawable/ic_folder_vd_theme_24 @drawable/ic_friction_lock_closed @drawable/ic_gray_scale_24dp @@ -71,9 +69,13 @@ @drawable/ic_settings_data_usage @drawable/ic_settings_date_time @drawable/ic_settings_delete + @drawable/ic_settings_disable @drawable/ic_settings_display_white + @drawable/ic_settings_enable @drawable/ic_settings_home + @drawable/ic_settings_language @drawable/ic_settings_location + @drawable/ic_settings_multiuser @drawable/ic_settings_night_display @drawable/ic_settings_open @drawable/ic_settings_print @@ -82,15 +84,16 @@ @drawable/ic_settings_sim @drawable/ic_settings_system_dashboard_white @drawable/ic_settings_wireless - @drawable/ic_settings_wireless_white @drawable/ic_storage @drawable/ic_storage_white @drawable/ic_suggestion_night_display @drawable/ic_sync + @drawable/ic_sync_problem_24dp @drawable/ic_system_update @drawable/ic_videogame_vd_theme_24 @drawable/ic_volume_ringer_vibrate @drawable/ic_volume_up_24dp @drawable/ic_vpn_key + @drawable/ic_wifi_tethering diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppStoragePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppStoragePreferenceControllerTest.java index 809d2cfefd1..065544b2f68 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppStoragePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppStoragePreferenceControllerTest.java @@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -99,6 +100,16 @@ public class AppStoragePreferenceControllerTest { verify(preference).setSummary(any()); } + @Test + public void updateState_entryIsNull_shouldNotUpdatePreferenceSummary() { + when(mFragment.getAppEntry()).thenReturn(null); + Preference preference = mock(Preference.class); + + mController.updateState(preference); + + verify(preference, never()).setSummary(any()); + } + @Test public void getStorageSummary_shouldWorkForExternal() { final StorageStatsSource.AppStorageStats stats = diff --git a/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceControllerTest.java new file mode 100644 index 00000000000..7f7fa4fed13 --- /dev/null +++ b/tests/robotests/src/com/android/settings/biometrics/face/FaceSettingsLockscreenBypassPreferenceControllerTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2019 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.biometrics.face; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.hardware.face.FaceManager; +import android.os.UserManager; +import android.provider.Settings; + +import androidx.preference.SwitchPreference; + +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.util.ReflectionHelpers; + +@RunWith(RobolectricTestRunner.class) +public class FaceSettingsLockscreenBypassPreferenceControllerTest { + + @Mock + private FaceManager mFaceManager; + private SwitchPreference mPreference; + @Mock + private UserManager mUserManager; + + private Context mContext; + private FaceSettingsLockscreenBypassPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mPreference = new SwitchPreference(mContext); + + mController = new FaceSettingsLockscreenBypassPreferenceController(mContext, "test_key"); + ReflectionHelpers.setField(mController, "mFaceManager", mFaceManager); + ReflectionHelpers.setField(mController, "mUserManager", mUserManager); + } + + @Test + public void isAvailable_whenHardwareDetected() { + assertThat(mController.isAvailable()).isFalse(); + when(mFaceManager.isHardwareDetected()).thenReturn(true); + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_isManagedProfile_shouldReturnUnsupported() { + when(mUserManager.isManagedProfile(anyInt())).thenReturn(true); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void onPreferenceChange_settingIsUpdated() { + boolean defaultValue = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_faceAuthDismissesKeyguard); + boolean state = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, defaultValue ? 1 : 0) != 0; + + assertThat(mController.onPreferenceChange(mPreference, !state)).isTrue(); + boolean newState = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD, 0) != 0; + assertThat(newState).isEqualTo(!state); + } +} diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java index adddc961e06..950d96237d6 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java @@ -31,12 +31,9 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.util.FeatureFlagUtils; import androidx.preference.Preference; -import com.android.settings.core.FeatureFlags; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -91,7 +88,7 @@ public class MainlineModuleVersionPreferenceControllerTest { @Test public void getAvailabilityStatus_hasMainlineModulePackageInfo_available() throws Exception { - setupModulePackage(); + setupModulePackage("test version 123"); final MainlineModuleVersionPreferenceController controller = new MainlineModuleVersionPreferenceController(mContext, "key"); @@ -101,7 +98,7 @@ public class MainlineModuleVersionPreferenceControllerTest { @Test public void updateStates_canHandleIntent_setIntentToPreference() throws Exception { - setupModulePackage(); + setupModulePackage("test version 123"); when(mPackageManager.resolveActivity(MODULE_UPDATE_INTENT, 0)) .thenReturn(new ResolveInfo()); @@ -115,7 +112,7 @@ public class MainlineModuleVersionPreferenceControllerTest { @Test public void updateStates_cannotHandleIntent_setNullToPreference() throws Exception { - setupModulePackage(); + setupModulePackage("test version 123"); when(mPackageManager.resolveActivity(MODULE_UPDATE_INTENT, 0)) .thenReturn(null); @@ -127,9 +124,38 @@ public class MainlineModuleVersionPreferenceControllerTest { assertThat(mPreference.getIntent()).isNull(); } - private void setupModulePackage() throws Exception { + @Test + public void getSummary_versionIsNull_returnNull() throws Exception { + setupModulePackage(null); + + final MainlineModuleVersionPreferenceController controller = + new MainlineModuleVersionPreferenceController(mContext, "key"); + + assertThat(controller.getSummary()).isNull(); + } + + @Test + public void getSummary_versionIsMonth_returnMonth() throws Exception { + setupModulePackage("2019-05"); + + final MainlineModuleVersionPreferenceController controller = + new MainlineModuleVersionPreferenceController(mContext, "key"); + + assertThat(controller.getSummary()).isEqualTo("May 01, 2019"); + } + + @Test + public void getSummary_versionIsDate_returnDate() throws Exception { + setupModulePackage("2019-05-13"); + + final MainlineModuleVersionPreferenceController controller = + new MainlineModuleVersionPreferenceController(mContext, "key"); + + assertThat(controller.getSummary()).isEqualTo("May 13, 2019"); + } + + private void setupModulePackage(String version) throws Exception { final String provider = "test.provider"; - final String version = "test version 123"; final PackageInfo info = new PackageInfo(); info.versionName = version; when(mContext.getString( diff --git a/tests/robotests/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceControllerTest.java new file mode 100644 index 00000000000..f2edf980443 --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/AdaptiveSleepPermissionPreferenceControllerTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2019 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.display; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.verify; + +import android.Manifest; +import android.content.Context; +import android.content.pm.PackageManager; + +import androidx.preference.Preference; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class AdaptiveSleepPermissionPreferenceControllerTest { + private final static String PACKAGE_NAME = "package_name"; + private AdaptiveSleepPermissionPreferenceController mController; + @Mock + private PackageManager mPackageManager; + @Mock + private Preference mPreference; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + Context context = Mockito.spy(RuntimeEnvironment.application); + doReturn(mPackageManager).when(context).getPackageManager(); + doReturn(PACKAGE_NAME).when(mPackageManager).getAttentionServicePackageName(); + doReturn(PackageManager.PERMISSION_GRANTED).when(mPackageManager).checkPermission( + Manifest.permission.CAMERA, PACKAGE_NAME); + mController = new AdaptiveSleepPermissionPreferenceController(context, "test_key"); + doReturn(mController.getPreferenceKey()).when(mPreference).getKey(); + } + + @Test + public void getAvailabilityStatus_returnAvailableUnsearchable() { + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE_UNSEARCHABLE); + } + + @Test + public void updateStates_permissionGranted_preferenceInvisible() { + mController.updateState(mPreference); + + verify(mPreference).setVisible(false); + } + + @Test + public void updateStates_permissionRevoked_preferenceVisible() { + doReturn(PackageManager.PERMISSION_DENIED).when(mPackageManager).checkPermission( + Manifest.permission.CAMERA, PACKAGE_NAME); + + mController.updateState(mPreference); + + verify(mPreference).setVisible(true); + } +} diff --git a/tests/robotests/src/com/android/settings/gestures/SystemNavigationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/gestures/SystemNavigationPreferenceControllerTest.java index 79f18502c81..3163f9ab801 100644 --- a/tests/robotests/src/com/android/settings/gestures/SystemNavigationPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/gestures/SystemNavigationPreferenceControllerTest.java @@ -24,7 +24,6 @@ import static com.android.settings.gestures.SystemNavigationPreferenceController import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import android.content.ComponentName; @@ -181,46 +180,4 @@ public class SystemNavigationPreferenceControllerTest { assertThat(TextUtils.equals(mController.getSummary(), mContext.getText( com.android.settings.R.string.swipe_up_to_switch_apps_title))).isTrue(); } - - @Test - public void testIsGestureNavSupportedByDefaultLauncher_noDefaultLauncher() { - when(mMockPackageManager.getHomeActivities(any())).thenReturn(null); - assertThat(SystemNavigationPreferenceController - .isGestureNavSupportedByDefaultLauncher(mMockContext)).isTrue(); - } - - @Test - public void testIsGestureNavSupportedByDefaultLauncher_supported() { - when(mMockPackageManager.getHomeActivities(any())).thenReturn( - ComponentName.unflattenFromString(TEST_RECENTS_COMPONENT_NAME)); - assertThat(SystemNavigationPreferenceController - .isGestureNavSupportedByDefaultLauncher(mMockContext)).isTrue(); - } - - @Test - public void testIsGestureNavSupportedByDefaultLauncher_notSupported() { - when(mMockPackageManager.getHomeActivities(any())).thenReturn( - new ComponentName("unsupported", "launcher")); - assertThat(SystemNavigationPreferenceController - .isGestureNavSupportedByDefaultLauncher(mMockContext)).isFalse(); - } - - @Test - public void testGetDefaultHomeAppName_noDefaultLauncher() { - when(mMockPackageManager.getHomeActivities(any())).thenReturn(null); - assertThat(SystemNavigationPreferenceController - .getDefaultHomeAppName(mMockContext)).isEqualTo(""); - } - - @Test - public void testGetDefaultHomeAppName_defaultLauncherExists() throws Exception { - when(mMockPackageManager.getHomeActivities(any())).thenReturn( - new ComponentName("supported", "launcher")); - ApplicationInfo info = new ApplicationInfo(); - when(mMockPackageManager.getApplicationInfo("supported", 0)).thenReturn(info); - when(mMockPackageManager.getApplicationLabel(info)).thenReturn("Test Home App"); - - assertThat(SystemNavigationPreferenceController - .getDefaultHomeAppName(mMockContext)).isEqualTo("Test Home App"); - } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ContextualAdaptiveSleepSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ContextualAdaptiveSleepSliceTest.java new file mode 100644 index 00000000000..54fb2c3281a --- /dev/null +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/ContextualAdaptiveSleepSliceTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2019 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.homepage.contextualcards.slices; + +import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.DEFERRED_TIME_DAYS; +import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF; +import static com.android.settings.homepage.contextualcards.slices.ContextualAdaptiveSleepSlice.PREF_KEY_SETUP_TIME; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.net.Uri; + +import androidx.slice.Slice; +import androidx.slice.SliceProvider; +import androidx.slice.widget.SliceLiveData; + +import com.android.settings.slices.CustomSliceRegistry; + +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; + +@RunWith(RobolectricTestRunner.class) +public class ContextualAdaptiveSleepSliceTest { + + private static final String pkgName = "adaptive_sleep"; + private Context mContext; + private ContextualAdaptiveSleepSlice mContextualAdaptiveSleepSlice; + @Mock + private PackageManager mPackageManager; + @Mock + private SharedPreferences mSharedPreferences; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); + mContext = spy(RuntimeEnvironment.application); + mContextualAdaptiveSleepSlice = spy(new ContextualAdaptiveSleepSlice(mContext)); + + doReturn(mPackageManager).when(mContext).getPackageManager(); + doReturn(mSharedPreferences).when(mContext).getSharedPreferences(eq(PREF), anyInt()); + doReturn(true).when(mContextualAdaptiveSleepSlice).isSettingsAvailable(); + doReturn(pkgName).when(mPackageManager).getAttentionServicePackageName(); + doReturn(-DEFERRED_TIME_DAYS).when(mSharedPreferences).getLong(eq(PREF_KEY_SETUP_TIME), + anyLong()); + } + + @Test + public void getUri_shouldReturnContextualAdaptiveSleepSliceUri() { + final Uri uri = mContextualAdaptiveSleepSlice.getUri(); + + assertThat(uri).isEqualTo(CustomSliceRegistry.CONTEXTUAL_ADAPTIVE_SLEEP_URI); + } + + @Test + public void getSlice_ShowIfFeatureIsAvailable() { + final Slice slice = mContextualAdaptiveSleepSlice.getSlice(); + + assertThat(slice).isNotNull(); + } + + @Test + public void getSlice_DoNotShowIfFeatureIsUnavailable() { + doReturn(false).when(mContextualAdaptiveSleepSlice).isSettingsAvailable(); + + final Slice slice = mContextualAdaptiveSleepSlice.getSlice(); + + assertThat(slice).isNull(); + } + + @Test + public void getSlice_ShowIfNotRecentlySetup() { + final Slice slice = mContextualAdaptiveSleepSlice.getSlice(); + + assertThat(slice).isNotNull(); + } + + @Test + public void getSlice_DoNotShowIfRecentlySetup() { + doReturn(System.currentTimeMillis()).when(mSharedPreferences).getLong( + eq(PREF_KEY_SETUP_TIME), anyLong()); + + final Slice slice = mContextualAdaptiveSleepSlice.getSlice(); + + assertThat(slice).isNull(); + } +} diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/FaceSetupSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/FaceSetupSliceTest.java new file mode 100644 index 00000000000..71b5c7a9b78 --- /dev/null +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/FaceSetupSliceTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2019 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.homepage.contextualcards.slices; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.hardware.face.FaceManager; +import android.os.UserHandle; + +import androidx.slice.Slice; +import androidx.slice.SliceProvider; +import androidx.slice.widget.SliceLiveData; + +import com.android.settings.R; +import com.android.settings.Utils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class FaceSetupSliceTest { + + private Context mContext; + private PackageManager mPackageManager; + + @Before + public void setUp() { + // Set-up specs for SliceMetadata. + SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); + mContext = spy(RuntimeEnvironment.application); + mPackageManager = mock(PackageManager.class); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + } + + @Test + public void getSlice_noFaceManager_shouldReturnNull() { + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false); + final FaceSetupSlice setupSlice = new FaceSetupSlice(mContext); + assertThat(setupSlice.getSlice()).isNull(); + } + + @Test + public void getSlice_faceEnrolled_shouldReturnNull() { + final FaceManager faceManager = mock(FaceManager.class); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true); + when(faceManager.hasEnrolledTemplates(UserHandle.myUserId())).thenReturn(true); + when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(faceManager); + final FaceSetupSlice setupSlice = new FaceSetupSlice(mContext); + assertThat(setupSlice.getSlice()).isNull(); + } + + @Test + public void getSlice_faceNotEnrolled_shouldReturnNonNull() { + final FaceManager faceManager = mock(FaceManager.class); + when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(true); + when(faceManager.hasEnrolledTemplates(UserHandle.myUserId())).thenReturn(false); + when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(faceManager); + final FaceSetupSlice setupSlice = new FaceSetupSlice(mContext); + assertThat(setupSlice.getSlice()).isNotNull(); + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java index 99c9134c77d..e24b0f22a5b 100644 --- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java @@ -42,6 +42,7 @@ import android.text.TextUtils; import com.android.settings.network.telephony.MobileNetworkActivity; import com.android.settings.widget.AddPreference; +import com.android.settingslib.RestrictedLockUtils; import org.junit.After; import org.junit.Before; @@ -373,4 +374,12 @@ public class MobileNetworkSummaryControllerTest { verify(mPreference, atLeastOnce()).setAddWidgetEnabled(captor.capture()); assertThat(captor.getValue()).isTrue(); } + + @Test + public void onResume_disabledByAdmin_prefStaysDisabled() { + mPreference.setDisabledByAdmin(new RestrictedLockUtils.EnforcedAdmin()); + mController.displayPreference(mPreferenceScreen); + mController.onResume(); + verify(mPreference, never()).setEnabled(eq(true)); + } } diff --git a/tests/robotests/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java index ba8be908c79..6a12afd1e50 100644 --- a/tests/robotests/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceControllerTest.java @@ -16,6 +16,8 @@ package com.android.settings.network.telephony; +import static androidx.lifecycle.Lifecycle.Event.ON_START; + import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; @@ -23,19 +25,25 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import android.content.Context; +import android.net.Uri; import android.os.PersistableBundle; import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import androidx.lifecycle.LifecycleOwner; import androidx.preference.ListPreference; +import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settingslib.core.lifecycle.Lifecycle; import org.junit.Before; import org.junit.Test; @@ -48,6 +56,7 @@ import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class EnabledNetworkModePreferenceControllerTest { private static final int SUB_ID = 2; + public static final String KEY = "enabled_network"; @Mock private TelephonyManager mTelephonyManager; @@ -60,11 +69,14 @@ public class EnabledNetworkModePreferenceControllerTest { private EnabledNetworkModePreferenceController mController; private ListPreference mPreference; private Context mContext; + private LifecycleOwner mLifecycleOwner; + private Lifecycle mLifecycle; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - + mLifecycleOwner = () -> mLifecycle; + mLifecycle = new Lifecycle(mLifecycleOwner); mContext = spy(RuntimeEnvironment.application); doReturn(mTelephonyManager).when(mContext).getSystemService(Context.TELEPHONY_SERVICE); doReturn(mTelephonyManager).when(mContext).getSystemService(TelephonyManager.class); @@ -79,8 +91,8 @@ public class EnabledNetworkModePreferenceControllerTest { mPreference = new ListPreference(mContext); mPreference.setEntries(R.array.enabled_networks_choices); mPreference.setEntryValues(R.array.enabled_networks_values); - mController = new EnabledNetworkModePreferenceController(mContext, "enabled_network"); - mController.init(SUB_ID); + mController = new EnabledNetworkModePreferenceController(mContext, KEY); + mController.init(mLifecycle, SUB_ID); mPreference.setKey(mController.getPreferenceKey()); } @@ -106,7 +118,7 @@ public class EnabledNetworkModePreferenceControllerTest { mPersistableBundle.putBoolean(CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, true); - mController.init(SUB_ID); + mController.init(mLifecycle, SUB_ID); assertThat(mController.mShow4GForLTE).isTrue(); } @@ -161,4 +173,31 @@ public class EnabledNetworkModePreferenceControllerTest { Settings.Global.PREFERRED_NETWORK_MODE + SUB_ID, 0)).isNotEqualTo( TelephonyManager.NETWORK_MODE_LTE_GSM_WCDMA); } + + @Test + public void preferredNetworkModeNotification_preferenceUpdates() { + PreferenceScreen screen = mock(PreferenceScreen.class); + doReturn(mPreference).when(screen).findPreference(KEY); + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.PREFERRED_NETWORK_MODE + SUB_ID, + TelephonyManager.NETWORK_MODE_TDSCDMA_GSM_WCDMA); + mController.displayPreference(screen); + mController.updateState(mPreference); + mLifecycle.handleLifecycleEvent(ON_START); + + assertThat(Integer.parseInt(mPreference.getValue())).isEqualTo( + TelephonyManager.NETWORK_MODE_TDSCDMA_GSM_WCDMA); + assertThat(mPreference.getSummary()).isEqualTo("3G"); + + + Settings.Global.putInt(mContext.getContentResolver(), + Settings.Global.PREFERRED_NETWORK_MODE + SUB_ID, + TelephonyManager.NETWORK_MODE_GSM_ONLY); + final Uri uri = Settings.Global.getUriFor(Settings.Global.PREFERRED_NETWORK_MODE + SUB_ID); + mContext.getContentResolver().notifyChange(uri, null); + + assertThat(Integer.parseInt(mPreference.getValue())).isEqualTo( + TelephonyManager.NETWORK_MODE_GSM_ONLY); + assertThat(mPreference.getSummary()).isEqualTo("2G"); + } } diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkActivityTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkActivityTest.java index f38f2a2bb0c..43897d503d9 100644 --- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkActivityTest.java +++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkActivityTest.java @@ -22,7 +22,10 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -31,6 +34,7 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.provider.Settings; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -40,6 +44,8 @@ import android.view.View; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.view.menu.ContextMenuBuilder; import com.android.settings.R; +import com.android.settings.core.FeatureFlags; +import com.android.settings.development.featureflags.FeatureFlagPersistent; import com.android.settings.network.SubscriptionUtil; import com.google.android.material.bottomnavigation.BottomNavigationView; @@ -159,19 +165,56 @@ public class MobileNetworkActivityTest { @Test public void phoneChangeReceiver_ignoresStickyBroadcastFromBeforeRegistering() { Activity activity = Robolectric.setupActivity(Activity.class); - final int[] onChangeCallbackCount = {0}; + MobileNetworkActivity.PhoneChangeReceiver.Client client = mock( + MobileNetworkActivity.PhoneChangeReceiver.Client.class); MobileNetworkActivity.PhoneChangeReceiver receiver = - new MobileNetworkActivity.PhoneChangeReceiver(activity, () -> { - onChangeCallbackCount[0]++; - }); + new MobileNetworkActivity.PhoneChangeReceiver(activity, client); Intent intent = new Intent(TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED); activity.sendStickyBroadcast(intent); receiver.register(); - assertThat(onChangeCallbackCount[0]).isEqualTo(0); + verify(client, never()).onPhoneChange(); activity.sendStickyBroadcast(intent); - assertThat(onChangeCallbackCount[0]).isEqualTo(1); + verify(client, times(1)).onPhoneChange(); + } + + @Test + public void phoneChangeReceiver_ignoresCarrierConfigChangeForWrongSubscriptionId() { + Activity activity = Robolectric.setupActivity(Activity.class); + + MobileNetworkActivity.PhoneChangeReceiver.Client client = mock( + MobileNetworkActivity.PhoneChangeReceiver.Client.class); + doReturn(2).when(client).getSubscriptionId(); + + MobileNetworkActivity.PhoneChangeReceiver receiver = + new MobileNetworkActivity.PhoneChangeReceiver(activity, client); + + receiver.register(); + + Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, 3); + activity.sendBroadcast(intent); + verify(client, never()).onPhoneChange(); + } + + @Test + public void phoneChangeReceiver_dispatchesCarrierConfigChangeForCorrectSubscriptionId() { + Activity activity = Robolectric.setupActivity(Activity.class); + + MobileNetworkActivity.PhoneChangeReceiver.Client client = mock( + MobileNetworkActivity.PhoneChangeReceiver.Client.class); + doReturn(2).when(client).getSubscriptionId(); + + MobileNetworkActivity.PhoneChangeReceiver receiver = + new MobileNetworkActivity.PhoneChangeReceiver(activity, client); + + receiver.register(); + + Intent intent = new Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED); + intent.putExtra(CarrierConfigManager.EXTRA_SUBSCRIPTION_INDEX, 2); + activity.sendBroadcast(intent); + verify(client).onPhoneChange(); } @@ -207,4 +250,19 @@ public class MobileNetworkActivityTest { assertThat(bundle.getInt(Settings.EXTRA_SUB_ID)).isEqualTo(PREV_SUB_ID); } + + @Test + public void onNewIntent_newSubscriptionId_fragmentReplaced() { + FeatureFlagPersistent.setEnabled(mContext, FeatureFlags.NETWORK_INTERNET_V2, true); + + mSubscriptionInfos.add(mSubscriptionInfo); + mSubscriptionInfos.add(mSubscriptionInfo2); + SubscriptionUtil.setAvailableSubscriptionsForTesting(mSubscriptionInfos); + mMobileNetworkActivity.mCurSubscriptionId = PREV_SUB_ID; + + final Intent newIntent = new Intent(); + newIntent.putExtra(Settings.EXTRA_SUB_ID, CURRENT_SUB_ID); + mMobileNetworkActivity.onNewIntent(newIntent); + assertThat(mMobileNetworkActivity.mCurSubscriptionId).isEqualTo(CURRENT_SUB_ID); + } } diff --git a/tests/robotests/src/com/android/settings/network/telephony/WifiCallingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/telephony/WifiCallingPreferenceControllerTest.java index 42422f9e8e5..f795d618d33 100644 --- a/tests/robotests/src/com/android/settings/network/telephony/WifiCallingPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/telephony/WifiCallingPreferenceControllerTest.java @@ -127,10 +127,10 @@ public class WifiCallingPreferenceControllerTest { } @Test - public void updateState_wfcNonRoaming() { + public void updateState_nonRoaming_wfcCellularPreferred() { assertNull(mController.mSimCallManager); - mCarrierConfig.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false); - // update the config value by calling init again. + mCarrierConfig.putBoolean( + CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, true); mController.init(SUB_ID); mController.mImsManager = mImsManager; @@ -147,9 +147,10 @@ public class WifiCallingPreferenceControllerTest { } @Test - public void updateState_wfcRoaming() { + public void updateState_roaming_wfcWifiPreferred() { assertNull(mController.mSimCallManager); - + // useWfcHomeModeForRoaming is false by default. In order to check wfc in roaming mode. We + // need the device roaming, and not using home mode in roaming network. when(mImsManager.getWfcMode(true)).thenReturn( ImsConfig.WfcModeFeatureValueConstants.WIFI_PREFERRED); when(mImsManager.getWfcMode(false)).thenReturn( diff --git a/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java index c5bd555fa9a..6f3230cff4f 100644 --- a/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java @@ -18,36 +18,54 @@ package com.android.settings.wifi; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; +import android.content.res.Resources; +import android.telephony.SubscriptionManager; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class CellularFallbackPreferenceControllerTest { private static final String KEY_CELLULAR_FALLBACK = "wifi_cellular_data_fallback"; - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private Context mContext; - private CellularFallbackPreferenceController mController; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mController = new CellularFallbackPreferenceController(mContext, KEY_CELLULAR_FALLBACK); + + mController = spy(new CellularFallbackPreferenceController(RuntimeEnvironment.application, + KEY_CELLULAR_FALLBACK)); + } + + @Test + public void isAvailable_invalidActiveSubscriptionId_shouldReturnFalse() { + doReturn(SubscriptionManager.INVALID_SUBSCRIPTION_ID) + .when(mController).getActiveDataSubscriptionId(); + + assertThat(mController.isAvailable()).isFalse(); } @Test public void isAvailable_avoidBadWifiConfigIsFalse_shouldReturnTrue() { - when(mContext.getResources().getInteger( + final Resources resources = mock(Resources.class); + + doReturn(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) + .when(mController).getActiveDataSubscriptionId(); + doReturn(resources).when(mController).getResourcesForSubId(anyInt()); + when(resources.getInteger( com.android.internal.R.integer.config_networkAvoidBadWifi)) .thenReturn(0); @@ -56,10 +74,15 @@ public class CellularFallbackPreferenceControllerTest { @Test public void isAvailable_avoidBadWifiConfigIsTrue_shouldReturnFalse() { - when(mContext.getResources().getInteger( + final Resources resources = mock(Resources.class); + + doReturn(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) + .when(mController).getActiveDataSubscriptionId(); + doReturn(resources).when(mController).getResourcesForSubId(anyInt()); + when(resources.getInteger( com.android.internal.R.integer.config_networkAvoidBadWifi)) .thenReturn(1); assertThat(mController.isAvailable()).isFalse(); } -} +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java index 9a1dd4c0f82..010fb749f74 100644 --- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java @@ -114,7 +114,7 @@ public class WifiDetailPreferenceControllerTest { private static final int TX_LINK_SPEED = 123; private static final int RX_LINK_SPEED = 54; private static final String SSID = "ssid"; - private static final String MAC_ADDRESS = WifiInfo.DEFAULT_MAC_ADDRESS; + private static final String MAC_ADDRESS = "01:23:45:67:89:ab"; private static final String RANDOMIZED_MAC_ADDRESS = "RANDOMIZED_MAC_ADDRESS"; private static final String FACTORY_MAC_ADDRESS = "FACTORY_MAC_ADDRESS"; private static final String SECURITY = "None"; diff --git a/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java b/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java index 0739ef0ce23..24d1bcc85e2 100644 --- a/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java +++ b/tests/unit/src/com/android/settings/wifi/tether/TetherServiceTest.java @@ -458,7 +458,7 @@ public class TetherServiceTest extends ServiceTestCase { } @Override - int getDefaultDataSubscriptionId() { + int getActiveDataSubscriptionId() { return INVALID_SUBSCRIPTION_ID; } }