Merge "Changes to the trigger segment" into main
diff --git a/aconfig/accessibility/accessibility_flags.aconfig b/aconfig/accessibility/accessibility_flags.aconfig
index 3ed618b..3092b8f 100644
--- a/aconfig/accessibility/accessibility_flags.aconfig
+++ b/aconfig/accessibility/accessibility_flags.aconfig
@@ -21,6 +21,16 @@
}
flag {
+ name: "check_prebundled_is_preinstalled"
+ namespace: "accessibility"
+ description: "Checks that all 'prebundled' components, used for grouping, are also preinstalled"
+ bug: "353888087"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "edit_shortcuts_in_full_screen"
namespace: "accessibility"
description: "Show the edit shorcuts screen in full screen, since the shortcut options are increasing."
diff --git a/res/layout-land/bluetooth_audio_streams_qr_code.xml b/res/layout-land/bluetooth_audio_streams_qr_code.xml
new file mode 100644
index 0000000..b35bc65
--- /dev/null
+++ b/res/layout-land/bluetooth_audio_streams_qr_code.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:padding="25dp"
+ android:baselineAligned="false">
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="start"
+ android:textSize="15sp"
+ android:textColor="?android:attr/textColorPrimary" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <ImageView
+ android:id="@+id/qrcode_view"
+ android:layout_width="@dimen/qrcode_size"
+ android:layout_height="@dimen/qrcode_size"
+ android:contentDescription="@string/audio_streams_qr_code_page_image_label"
+ android:focusable="true" />
+
+ <TextView
+ android:id="@+id/password"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="15sp"
+ android:textColor="?android:attr/textColorPrimary" />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout-land/qrcode_scanner_fragment.xml b/res/layout-land/qrcode_scanner_fragment.xml
new file mode 100644
index 0000000..0e563e3
--- /dev/null
+++ b/res/layout-land/qrcode_scanner_fragment.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2022 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <TextView
+ android:id="@android:id/summary"
+ style="@style/QrCodeScanner"
+ android:gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="center"
+ android:orientation="vertical">
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:gravity="center"
+ android:clipChildren="true"
+ android:contentDescription="@string/audio_streams_qr_code_scanner_label"
+ android:focusable="true">
+ <TextureView
+ android:id="@+id/preview_view"
+ android:layout_marginStart="@dimen/qrcode_preview_margin"
+ android:layout_marginEnd="@dimen/qrcode_preview_margin"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/qrcode_preview_size"/>
+ </FrameLayout>
+
+ <TextView
+ android:id="@+id/error_message"
+ style="@style/TextAppearance.ErrorText"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="16dp"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:visibility="invisible"/>
+
+ </LinearLayout>
+
+
+</LinearLayout>
+
diff --git a/res/layout/advanced_bt_entity_sub.xml b/res/layout/advanced_bt_entity_sub.xml
index 90ac456..dd8e43a 100644
--- a/res/layout/advanced_bt_entity_sub.xml
+++ b/res/layout/advanced_bt_entity_sub.xml
@@ -45,7 +45,7 @@
android:layout_gravity="center"
android:indeterminate="false"
app:trackColor="@android:color/transparent"
- app:indicatorColor="@color/bluetooth_battery_ring_indicator_color"
+ app:indicatorColor="@color/settingslib_materialColorPrimary"
app:trackThickness="4dp"
app:indicatorSize="76dp"
app:indicatorInset="0dp"
diff --git a/res/xml/bluetooth_audio_streams_qr_code.xml b/res/layout/bluetooth_audio_streams_qr_code.xml
similarity index 91%
rename from res/xml/bluetooth_audio_streams_qr_code.xml
rename to res/layout/bluetooth_audio_streams_qr_code.xml
index 5ec5505..fd521fe 100644
--- a/res/xml/bluetooth_audio_streams_qr_code.xml
+++ b/res/layout/bluetooth_audio_streams_qr_code.xml
@@ -47,7 +47,9 @@
<ImageView
android:id="@+id/qrcode_view"
android:layout_width="@dimen/qrcode_size"
- android:layout_height="@dimen/qrcode_size"/>
+ android:layout_height="@dimen/qrcode_size"
+ android:contentDescription="@string/audio_streams_qr_code_page_image_label"
+ android:focusable="true"/>
<TextView
android:id="@+id/password"
diff --git a/res/layout/qrcode_scanner_fragment.xml b/res/layout/qrcode_scanner_fragment.xml
index 4f748c5..72049a4 100644
--- a/res/layout/qrcode_scanner_fragment.xml
+++ b/res/layout/qrcode_scanner_fragment.xml
@@ -55,7 +55,9 @@
android:layout_height="wrap_content"
android:layout_gravity="top"
android:gravity="center"
- android:clipChildren="true">
+ android:clipChildren="true"
+ android:contentDescription="@string/audio_streams_qr_code_scanner_label"
+ android:focusable="true">
<TextureView
android:id="@+id/preview_view"
android:layout_marginStart="@dimen/qrcode_preview_margin"
diff --git a/res/values/colors.xml b/res/values/colors.xml
index b0de870..6d92526 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -218,7 +218,4 @@
<!-- Switch bar disabled state color-->
<color name="switch_bar_state_disabled_color">#1F1F1F1F</color>
-
- <!-- Battery ring indicator color in bluetooth device details -->
- <color name="bluetooth_battery_ring_indicator_color">#9ED582</color>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 08d29ea..84eb74f 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5477,6 +5477,8 @@
<string name="daltonizer_mode_grayscale_title">Grayscale</string>
<!-- Title shown for settings that controls color correction saturation level [CHAR LIMIT=45] -->
<string name="daltonizer_saturation_title">Intensity</string>
+ <!-- The summary shown for settings that controls color correction intensity/saturation level. It is shown when intensity slider is grayed out and is not usable and it explains why it's not usable to the user. [CHAR LIMIT=NONE] -->
+ <string name="daltonizer_saturation_unavailable_summary">Unavailable for grayscale mode or when color correction is disabled</string>
<!-- Summary shown for deuteranomaly (red-green color blindness) [CHAR LIMIT=45] -->
<string name="daltonizer_mode_deuteranomaly_summary">Green weak, deuteranomaly</string>
<!-- Summary shown for protanomaly (red-green color blindness) [CHAR LIMIT=45] -->
@@ -12253,16 +12255,11 @@
<!-- Default title for the settings panel [CHAR LIMIT=NONE] -->
<string name="settings_panel_title">Settings Panel</string>
- <!-- Title for enabling freeform windows (desktop mode) developer option toggle [CHAR LIMIT=50] -->
- <string name="enable_desktop_mode">Enable freeform windows</string>
- <!-- Summary for enabling freeform windows (desktop mode) developer option toggle [CHAR LIMIT=NONE] -->
- <string name="enable_desktop_mode_summary">Enable support for freeform windows.</string>
+ <!-- Title for a toggle that enables freeform windowing experiences. Freeform windowing experiences are features involving apps running in resizable windows. [CHAR LIMIT=50] -->
+ <string name="enable_desktop_mode">Enable freeform windowing experiences</string>
- <!-- TODO(b/348193756): Rename resources for this toggle to indicate that it is for secondary display -->
- <!-- Title for enabling freeform windows (desktop mode) on secondary display developer option toggle [CHAR LIMIT=50] -->
- <string name="force_desktop_mode">Enable freeform windowing on second display</string>
- <!-- Summary for enabling freeform windows (desktop mode) on secondary display developer option toggle [CHAR LIMIT=NONE] -->
- <string name="force_desktop_mode_summary">Enable freeform windows only on secondary display.</string>
+ <!-- Title for a toggle that enables desktop mode on secondary display. [CHAR LIMIT=50] -->
+ <string name="enable_desktop_mode_on_secondary_display">Enable desktop mode on secondary display</string>
<!-- UI debug setting: enable non-resizables in multi window [CHAR LIMIT=60] -->
<string name="enable_non_resizable_multi_window">Enable non-resizable in multi window</string>
@@ -13225,14 +13222,12 @@
<!-- The content description for accessibility tools of the customize button. It specifies which screensaver the user is customizing [CHAR LIMIT=NONE] -->
<string name="customize_button_description">Customize <xliff:g id="screensaver_name" example="Art Gallery">%1$s</xliff:g></string>
- <!-- Dialog body text used to explain a reboot is required after enabling freeform support for
- it to work [CHAR LIMIT=none] -->
- <string name="reboot_dialog_enable_freeform_support">A reboot is required to enable legacy freeform windowing support.</string>
- <!-- Dialog body text used to explain a reboot is required after overriding freeform windowing (desktop mode) support. [CHAR LIMIT=none] -->
- <string name="reboot_dialog_override_desktop_mode">A reboot is required to change freeform windowing support.</string>
- <!-- Dialog body text used to explain a reboot is required after forcing freeform windowing (desktop mode) on
- secondary displays. [CHAR LIMIT=none] -->
- <string name="reboot_dialog_force_desktop_mode">A reboot is required to force freeform windowing on secondary displays.</string>
+ <!-- Dialog body text used to explain a reboot is required after enabling freeform window support for it to work. Freeform window is when an app runs in a resizable window. [CHAR LIMIT=none] -->
+ <string name="reboot_dialog_enable_freeform_support">A reboot is required to enable freeform window support.</string>
+ <!-- Dialog body text used to explain a reboot is required after updating availability of freeform windowing experiences. Freeform windowing experiences are features involving apps running in resizable windows. [CHAR LIMIT=none] -->
+ <string name="reboot_dialog_override_desktop_mode">A reboot is required to update availability of freeform windowing experiences.</string>
+ <!-- Dialog body text used to explain a reboot is required after enabling desktop mode on secondary displays. [CHAR LIMIT=none] -->
+ <string name="reboot_dialog_enable_desktop_mode_on_secondary_display">A reboot is required to enable desktop mode on secondary displays.</string>
<!-- Text on the dialog button to reboot the device now [CHAR LIMIT=50] -->
<string name="reboot_dialog_reboot_now">Reboot now</string>
<!-- Text on the dialog button to reboot the device later [CHAR LIMIT=50] -->
@@ -13757,6 +13752,10 @@
<string name="audio_streams_main_page_qr_code_scanner_summary">Scan an audio stream QR code to listen with <xliff:g example="LE headset" id="device_name">%1$s</xliff:g></string>
<!-- Le audio streams password dialog [CHAR LIMIT=NONE] -->
<string name="audio_streams_main_page_password_dialog_cannot_edit">Can\u0027t edit password while sharing. To change the password, first turn off audio sharing.</string>
+ <!-- Text for audio sharing qrcode image [CHAR LIMIT=none]-->
+ <string name="audio_streams_qr_code_page_image_label">QR code</string>
+ <!-- Text for audio sharing qrcode scanner [CHAR LIMIT=none]-->
+ <string name="audio_streams_qr_code_scanner_label">QR code scanner</string>
<!-- url for learning more about bluetooth audio sharing -->
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index 9420f59..88abadb 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -739,18 +739,15 @@
<SwitchPreferenceCompat
android:key="override_desktop_mode_features"
- android:title="@string/enable_desktop_mode"
- android:summary="@string/enable_desktop_mode_summary" />
+ android:title="@string/enable_desktop_mode" />
<SwitchPreferenceCompat
android:key="enable_freeform_support"
- android:title="@string/enable_freeform_support"
- android:summary="@string/enable_freeform_support_summary" />
+ android:title="@string/enable_freeform_support" />
<SwitchPreferenceCompat
android:key="force_desktop_mode_on_external_displays"
- android:title="@string/force_desktop_mode"
- android:summary="@string/force_desktop_mode_summary" />
+ android:title="@string/enable_desktop_mode_on_secondary_display"/>
<SwitchPreferenceCompat
android:key="enable_non_resizable_multi_window"
diff --git a/src/com/android/settings/MainClear.java b/src/com/android/settings/MainClear.java
index 9d219d7..9dadcb9 100644
--- a/src/com/android/settings/MainClear.java
+++ b/src/com/android/settings/MainClear.java
@@ -182,10 +182,13 @@
}
if (requestCode == KEYGUARD_REQUEST) {
+ final int userId = getActivity().getUserId();
if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
false /* biometricsSuccessfullyAuthenticated */,
- false /* biometricsAuthenticationRequested */)) {
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRICS_REQUEST);
+ false /* biometricsAuthenticationRequested */,
+ userId)) {
+ Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRICS_REQUEST,
+ userId);
return;
}
}
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index e94769a..add5604 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -1487,23 +1487,25 @@
/**
* Request biometric authentication if all requirements for mandatory biometrics is satisfied.
- * @param context of the corresponding activity/fragment
+ *
+ * @param context of the corresponding activity/fragment
* @param biometricsSuccessfullyAuthenticated if the user has already authenticated using
* biometrics
- * @param biometricsAuthenticationRequested if the activity/fragment has already requested for
- * biometric prompt
+ * @param biometricsAuthenticationRequested if the activity/fragment has already requested for
+ * biometric prompt
+ * @param userId user id for the authentication request
* @return true if all requirements for mandatory biometrics is satisfied
*/
public static boolean requestBiometricAuthenticationForMandatoryBiometrics(
@NonNull Context context,
boolean biometricsSuccessfullyAuthenticated,
- boolean biometricsAuthenticationRequested) {
+ boolean biometricsAuthenticationRequested, int userId) {
final BiometricManager biometricManager = context.getSystemService(BiometricManager.class);
if (biometricManager == null) {
Log.e(TAG, "Biometric Manager is null.");
return false;
}
- final int status = biometricManager.canAuthenticate(
+ final int status = biometricManager.canAuthenticate(userId,
BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
return android.hardware.biometrics.Flags.mandatoryBiometrics()
&& status == BiometricManager.BIOMETRIC_SUCCESS
@@ -1513,15 +1515,16 @@
/**
* Launch biometric prompt for mandatory biometrics. Call
- * {@link #requestBiometricAuthenticationForMandatoryBiometrics(Context, boolean, boolean)}
+ * {@link #requestBiometricAuthenticationForMandatoryBiometrics(Context, boolean, boolean, int)}
* to check if all requirements for mandatory biometrics is satisfied
* before launching biometric prompt.
*
- * @param fragment corresponding fragment of the surface
+ * @param fragment corresponding fragment of the surface
* @param requestCode for starting the new activity
+ * @param userId user id for the authentication request
*/
public static void launchBiometricPromptForMandatoryBiometrics(@NonNull Fragment fragment,
- int requestCode) {
+ int requestCode, int userId) {
final Intent intent = new Intent();
intent.putExtra(BIOMETRIC_PROMPT_AUTHENTICATORS,
BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
@@ -1529,8 +1532,10 @@
fragment.getString(R.string.cancel));
intent.putExtra(KeyguardManager.EXTRA_DESCRIPTION,
fragment.getString(R.string.mandatory_biometrics_prompt_description));
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, true);
+ intent.putExtra(EXTRA_USER_ID, userId);
intent.setClassName(SETTINGS_PACKAGE_NAME,
- ConfirmDeviceCredentialActivity.class.getName());
+ ConfirmDeviceCredentialActivity.InternalActivity.class.getName());
fragment.startActivityForResult(intent, requestCode);
}
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 23f8ec7..d01806a 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -75,7 +75,8 @@
private static final String CATEGORY_AUDIO = "audio_category";
private static final String CATEGORY_SPEECH = "speech_category";
private static final String CATEGORY_DISPLAY = "display_category";
- private static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
+ @VisibleForTesting
+ static final String CATEGORY_DOWNLOADED_SERVICES = "user_installed_services_category";
private static final String CATEGORY_KEYBOARD_OPTIONS = "physical_keyboard_options_category";
@VisibleForTesting
static final String CATEGORY_INTERACTION_CONTROL = "interaction_control_category";
@@ -380,6 +381,7 @@
}
protected void updateServicePreferences() {
+ final AccessibilityManager a11yManager = AccessibilityManager.getInstance(getPrefContext());
// Since services category is auto generated we have to do a pass
// to generate it since services can come and go and then based on
// the global accessibility state to decided whether it is enabled.
@@ -410,8 +412,18 @@
AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM,
mCategoryToPrefCategoryMap.get(CATEGORY_INTERACTION_CONTROL));
- final List<RestrictedPreference> preferenceList = getInstalledAccessibilityList(
- getPrefContext());
+ final List<AccessibilityShortcutInfo> installedShortcutList =
+ a11yManager.getInstalledAccessibilityShortcutListAsUser(getPrefContext(),
+ UserHandle.myUserId());
+ final List<AccessibilityServiceInfo> modifiableInstalledServiceList =
+ new ArrayList<>(a11yManager.getInstalledAccessibilityServiceList());
+ final List<RestrictedPreference> preferenceList = getInstalledAccessibilityPreferences(
+ getPrefContext(), installedShortcutList, modifiableInstalledServiceList);
+
+ if (Flags.checkPrebundledIsPreinstalled()) {
+ removeNonPreinstalledComponents(mPreBundledServiceComponentToCategoryMap,
+ installedShortcutList, modifiableInstalledServiceList);
+ }
final PreferenceCategory downloadedServicesCategory =
mCategoryToPrefCategoryMap.get(CATEGORY_DOWNLOADED_SERVICES);
@@ -456,13 +468,21 @@
updatePreferenceCategoryVisibility(CATEGORY_KEYBOARD_OPTIONS);
}
- private List<RestrictedPreference> getInstalledAccessibilityList(Context context) {
- final AccessibilityManager a11yManager = AccessibilityManager.getInstance(context);
+ /**
+ * Gets a list of {@link RestrictedPreference}s for the provided a11y shortcuts and services.
+ *
+ * <p>{@code modifiableInstalledServiceList} may be modified to remove any entries with
+ * matching package name and label as an entry in {@code installedShortcutList}.
+ *
+ * @param installedShortcutList A list of installed {@link AccessibilityShortcutInfo}s.
+ * @param modifiableInstalledServiceList A modifiable list of installed
+ * {@link AccessibilityServiceInfo}s.
+ */
+ private List<RestrictedPreference> getInstalledAccessibilityPreferences(Context context,
+ List<AccessibilityShortcutInfo> installedShortcutList,
+ List<AccessibilityServiceInfo> modifiableInstalledServiceList) {
final RestrictedPreferenceHelper preferenceHelper = new RestrictedPreferenceHelper(context);
- final List<AccessibilityShortcutInfo> installedShortcutList =
- a11yManager.getInstalledAccessibilityShortcutListAsUser(context,
- UserHandle.myUserId());
final List<AccessibilityActivityPreference> activityList =
preferenceHelper.createAccessibilityActivityPreferenceList(installedShortcutList);
final Set<Pair<String, CharSequence>> packageLabelPairs =
@@ -471,16 +491,14 @@
a11yActivityPref.getPackageName(), a11yActivityPref.getLabel())
).collect(Collectors.toSet());
- // Remove duplicate item here, new a ArrayList to copy unmodifiable list result
- // (getInstalledAccessibilityServiceList).
- final List<AccessibilityServiceInfo> installedServiceList = new ArrayList<>(
- a11yManager.getInstalledAccessibilityServiceList());
+ // Remove duplicate A11yServices that are already shown as A11yActivities.
if (!packageLabelPairs.isEmpty()) {
- installedServiceList.removeIf(
+ modifiableInstalledServiceList.removeIf(
target -> containsPackageAndLabelInList(packageLabelPairs, target));
}
final List<RestrictedPreference> serviceList =
- preferenceHelper.createAccessibilityServicePreferenceList(installedServiceList);
+ preferenceHelper.createAccessibilityServicePreferenceList(
+ modifiableInstalledServiceList);
final List<RestrictedPreference> preferenceList = new ArrayList<>();
preferenceList.addAll(activityList);
@@ -489,6 +507,22 @@
return preferenceList;
}
+ private static void removeNonPreinstalledComponents(
+ Map<ComponentName, PreferenceCategory> componentToCategory,
+ List<AccessibilityShortcutInfo> shortcutInfos,
+ List<AccessibilityServiceInfo> serviceInfos) {
+ for (AccessibilityShortcutInfo info : shortcutInfos) {
+ if (!info.getActivityInfo().applicationInfo.isSystemApp()) {
+ componentToCategory.remove(info.getComponentName());
+ }
+ }
+ for (AccessibilityServiceInfo info : serviceInfos) {
+ if (!info.getResolveInfo().serviceInfo.applicationInfo.isSystemApp()) {
+ componentToCategory.remove(info.getComponentName());
+ }
+ }
+ }
+
private boolean containsPackageAndLabelInList(
Set<Pair<String, CharSequence>> packageLabelPairs,
AccessibilityServiceInfo targetServiceInfo) {
diff --git a/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceController.java b/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceController.java
index 7dcd661..2997185 100644
--- a/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceController.java
+++ b/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceController.java
@@ -17,26 +17,50 @@
import android.content.ContentResolver;
import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
import android.provider.Settings;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.server.accessibility.Flags;
+import com.android.settings.R;
import com.android.settings.core.SliderPreferenceController;
import com.android.settings.widget.SeekBarPreference;
/**
* The controller of the seekbar preference for the saturation level of color correction.
*/
-public class DaltonizerSaturationSeekbarPreferenceController extends SliderPreferenceController {
+public class DaltonizerSaturationSeekbarPreferenceController
+ extends SliderPreferenceController
+ implements DefaultLifecycleObserver {
private static final int DEFAULT_SATURATION_LEVEL = 7;
private static final int SATURATION_MAX = 10;
- private static final int SATURATION_MIN = 0;
+ private static final int SATURATION_MIN = 1;
private int mSliderPosition;
private final ContentResolver mContentResolver;
+ @Nullable
+ private SeekBarPreference mPreference;
+
+ public final ContentObserver mContentObserver = new ContentObserver(
+ new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange) {
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
+ }
+ };
+
public DaltonizerSaturationSeekbarPreferenceController(Context context,
String preferenceKey) {
super(context, preferenceKey);
@@ -50,9 +74,32 @@
}
@Override
+ public void onStart(@NonNull LifecycleOwner owner) {
+ if (!isAvailable()) return;
+ mContentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
+ true,
+ mContentObserver
+ );
+ mContentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
+ true,
+ mContentObserver
+ );
+ }
+
+ @Override
+ public void onStop(@NonNull LifecycleOwner owner) {
+ if (!isAvailable()) return;
+ mContentResolver.unregisterContentObserver(mContentObserver);
+ mPreference = null;
+ }
+
+ @Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
SeekBarPreference preference = screen.findPreference(getPreferenceKey());
+ mPreference = preference;
preference.setMax(getMax());
preference.setMin(getMin());
preference.setProgress(mSliderPosition);
@@ -62,7 +109,7 @@
@Override
public int getAvailabilityStatus() {
if (Flags.enableColorCorrectionSaturation()) {
- return AVAILABLE;
+ return shouldSeekBarEnabled() ? AVAILABLE : DISABLED_DEPENDENT_SETTING;
}
return CONDITIONALLY_UNAVAILABLE;
}
@@ -86,6 +133,21 @@
}
@Override
+ public void updateState(Preference preference) {
+ if (preference == null) {
+ return;
+ }
+
+ var shouldSeekbarEnabled = shouldSeekBarEnabled();
+ // setSummary not working yet on SeekBarPreference.
+ String summary = shouldSeekbarEnabled
+ ? ""
+ : mContext.getString(R.string.daltonizer_saturation_unavailable_summary);
+ preference.setSummary(summary);
+ preference.setEnabled(shouldSeekbarEnabled);
+ }
+
+ @Override
public int getMax() {
return SATURATION_MAX;
}
@@ -94,4 +156,16 @@
public int getMin() {
return SATURATION_MIN;
}
+
+ private boolean shouldSeekBarEnabled() {
+ int enabled = Settings.Secure.getInt(
+ mContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0);
+ int mode = Settings.Secure.getInt(
+ mContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, -1);
+
+ // enabled == 0 is disabled and also default.
+ // mode == 0 is gray scale where saturation level isn't applicable.
+ // mode == -1 is disabled and also default.
+ return enabled != 0 && mode != -1 && mode != 0;
+ }
}
diff --git a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
index b9a0b93..835f3a8 100644
--- a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
+++ b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
@@ -144,9 +144,10 @@
launchChooseOrConfirmLock();
} else if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(
getActivity(), mBiometricsSuccessfullyAuthenticated,
- mBiometricsAuthenticationRequested)) {
+ mBiometricsAuthenticationRequested, mUserId)) {
mBiometricsAuthenticationRequested = true;
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+ Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+ mUserId);
}
updateUnlockPhonePreferenceSummary();
@@ -161,10 +162,11 @@
public void onResume() {
super.onResume();
if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
- mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested)
+ mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested, mUserId)
&& mGkPwHandle != 0L) {
mBiometricsAuthenticationRequested = true;
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+ Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+ mUserId);
}
if (!mConfirmCredential) {
mDoNotFinishActivity = false;
diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java
index 2a0dd83..305d670 100644
--- a/src/com/android/settings/biometrics/face/FaceSettings.java
+++ b/src/com/android/settings/biometrics/face/FaceSettings.java
@@ -289,9 +289,11 @@
finish();
}
} else if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
- mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested)) {
+ mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested,
+ mUserId)) {
mBiometricsAuthenticationRequested = true;
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+ Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+ mUserId);
} else {
mAttentionController.setToken(mToken);
mEnrollController.setToken(mToken);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index c4bbcde..815c08e 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -485,9 +485,11 @@
mLaunchedConfirm = true;
launchChooseOrConfirmLock();
} else if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
- mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested)) {
+ mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested,
+ mUserId)) {
mBiometricsAuthenticationRequested = true;
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+ Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+ mUserId);
} else if (!mHasFirstEnrolled) {
mIsEnrolling = true;
addFirstFingerprint(null);
@@ -777,9 +779,11 @@
.getUdfpsEnrollCalibrator(getActivity().getApplicationContext(), null, null);
if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
- mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested)) {
+ mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested,
+ mUserId)) {
mBiometricsAuthenticationRequested = true;
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+ Utils.launchBiometricPromptForMandatoryBiometrics(this,
+ BIOMETRIC_AUTH_REQUEST, mUserId);
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt b/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
index 215692a..9bc920a 100644
--- a/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
@@ -16,7 +16,9 @@
package com.android.settings.biometrics.fingerprint2
+import android.content.pm.PackageManager
import android.hardware.fingerprint.FingerprintManager
+import android.os.ServiceManager.ServiceNotFoundException
import android.view.MotionEvent
import android.view.accessibility.AccessibilityManager
import androidx.fragment.app.FragmentActivity
@@ -74,8 +76,15 @@
private val backgroundDispatcher = executorService.asCoroutineDispatcher()
private val applicationScope = MainScope()
private val gateKeeperPasswordProvider = GatekeeperPasswordProvider(LockPatternUtils(context))
- private val fingerprintManager =
- context.getSystemService(FragmentActivity.FINGERPRINT_SERVICE) as FingerprintManager?
+ private val fingerprintManager = try {
+ if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ context.getSystemService(FragmentActivity.FINGERPRINT_SERVICE) as FingerprintManager?
+ } else {
+ null
+ }
+ } catch (exception: ServiceNotFoundException){
+ null
+ }
private val fingerprintSensorRepository: FingerprintSensorRepository =
FingerprintSensorRepositoryImpl(fingerprintManager, backgroundDispatcher, applicationScope)
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java
index bfccdc4..0a90e7b 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java
@@ -92,6 +92,8 @@
shareButton.setVisibility(View.VISIBLE);
shareButton.setImageDrawable(getContext().getDrawable(R.drawable.ic_qrcode_24dp));
shareButton.setOnClickListener(unused -> launchAudioSharingQrCodeFragment());
+ shareButton.setContentDescription(
+ getContext().getString(R.string.audio_sharing_qrcode_button_label));
}
private void configureInvisibleStateForQrCodeIcon(ImageButton shareButton, View divider) {
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java
index e4c0794..47f9c75 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java
@@ -55,7 +55,7 @@
@Override
public final View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- return inflater.inflate(R.xml.bluetooth_audio_streams_qr_code, container, false);
+ return inflater.inflate(R.layout.bluetooth_audio_streams_qr_code, container, false);
}
@Override
diff --git a/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java b/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java
index ff513c2..0d3d835 100644
--- a/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java
+++ b/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java
@@ -69,7 +69,8 @@
isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
if (isEnabled && mFragment != null) {
RebootConfirmationDialogFragment.show(
- mFragment, R.string.reboot_dialog_force_desktop_mode, this);
+ mFragment, R.string.reboot_dialog_enable_desktop_mode_on_secondary_display,
+ this);
}
return true;
}
diff --git a/src/com/android/settings/development/FreeformWindowsPreferenceController.java b/src/com/android/settings/development/FreeformWindowsPreferenceController.java
index 7cf7738..c02ffa7 100644
--- a/src/com/android/settings/development/FreeformWindowsPreferenceController.java
+++ b/src/com/android/settings/development/FreeformWindowsPreferenceController.java
@@ -16,8 +16,9 @@
package com.android.settings.development;
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+
import android.content.Context;
-import android.os.Build;
import android.provider.Settings;
import androidx.annotation.Nullable;
@@ -40,7 +41,8 @@
@VisibleForTesting
static final int SETTING_VALUE_ON = 1;
- @Nullable private final DevelopmentSettingsDashboardFragment mFragment;
+ @Nullable
+ private final DevelopmentSettingsDashboardFragment mFragment;
public FreeformWindowsPreferenceController(
Context context, @Nullable DevelopmentSettingsDashboardFragment fragment) {
@@ -49,6 +51,13 @@
}
@Override
+ public boolean isAvailable() {
+ // When devices have the system feature FEATURE_FREEFORM_WINDOW_MANAGEMENT, freeform
+ // mode is enabled automatically, and this toggle is not needed.
+ return !mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+ }
+
+ @Override
public String getPreferenceKey() {
return ENABLE_FREEFORM_SUPPORT_KEY;
}
@@ -80,9 +89,4 @@
Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, SETTING_VALUE_OFF);
((TwoStatePreference) mPreference).setChecked(false);
}
-
- @VisibleForTesting
- String getBuildType() {
- return Build.TYPE;
- }
}
diff --git a/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceController.java b/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceController.java
index 23d4cc6..9f7512c 100644
--- a/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceController.java
+++ b/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceController.java
@@ -30,85 +30,184 @@
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+/**
+ * This preference represents the default log level for the Bluetooth stack
+ *
+ * The default log level is captured and held in an Android Log Framework log tag, using "bluetooth"
+ * as the tag name. The Log framework does not provide methods to directly write a log tag value,
+ * but instead leverages special system properties to hold the value of a log tag.
+ *
+ * This preferences aims to keep the selection in sync with the currently set log tag value. It
+ * writes directly to the system properties that hold the level associated with the bluetooth log
+ * tag. It leverages the Log.isLoggable("bluetooth", level) function to discern the current value.
+ * The default level is INFO.
+ *
+ * This value is read once at start of the Bluetooth stack. To use a new value once setting it, be
+ * sure to turn Bluetooth off and back on again.
+ */
public class BluetoothStackLogPreferenceController extends DeveloperOptionsPreferenceController
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+ private static final String TAG = BluetoothStackLogPreferenceController.class.getSimpleName();
+
+ private static final String PREFERENCE_KEY = "bt_stack_log_level";
/* Ensure that the indexes match with bt_stack_log_values and bt_stack_log_entries ordering */
- private static final String PREFERENCE_KEY = "bt_stack_log_level";
- @VisibleForTesting static final int BTSTACK_LOG_MODE_VERBOSE_INDEX = 0;
- @VisibleForTesting static final int BTSTACK_LOG_MODE_DEBUG_INDEX = 1;
- @VisibleForTesting static final int BTSTACK_LOG_MODE_INFO_INDEX = 2;
- @VisibleForTesting static final int BTSTACK_LOG_MODE_WARN_INDEX = 3;
- @VisibleForTesting static final int BTSTACK_LOG_MODE_ERROR_INDEX = 4;
+ private static final int BT_LOG_LEVEL_VERBOSE_INDEX = 0;
+ private static final int BT_LOG_LEVEL_DEBUG_INDEX = 1;
+ private static final int BT_LOG_LEVEL_INFO_INDEX = 2;
+ private static final int BT_LOG_LEVEL_WARN_INDEX = 3;
+ private static final int BT_LOG_LEVEL_ERROR_INDEX = 4;
+ @VisibleForTesting static final int BT_LOG_LEVEL_DEFAULT_INDEX = BT_LOG_LEVEL_INFO_INDEX;
- @VisibleForTesting
- static final String BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST = "persist.log.tag.bluetooth";
- static final String BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY = "log.tag.bluetooth";
- static final String BLUETOOTH_STRING_NAME = "bluetooth";
- static final int DEFAULT_MODE = BTSTACK_LOG_MODE_INFO_INDEX;
+ private static final String BT_LOG_TAG = "bluetooth";
+ @VisibleForTesting static final String BT_LOG_LEVEL_PROP_PERSIST = "persist.log.tag.bluetooth";
+ @VisibleForTesting static final String BT_LOG_LEVEL_PROP = "log.tag.bluetooth";
- private final String[] mListValues;
- private final String[] mListEntries;
+ // Values represents the untranslatable log level strings that should be used for writing to
+ // system properties. Entries represents the translatable log level strings that should be used
+ // in the UI to communicate to the user their options for this preference.
+ private String[] mListValues;
+ private String[] mListEntries;
-
+ /**
+ * Create a BluetoothStackLogPreferenceController instance
+ */
public BluetoothStackLogPreferenceController(@NonNull Context context) {
super(context);
mListValues = context.getResources().getStringArray(R.array.bt_stack_log_level_values);
mListEntries = context.getResources().getStringArray(R.array.bt_stack_log_level_entries);
}
- /** returns default log level index of INFO */
- public int getDefaultModeIndex() {
- return DEFAULT_MODE;
- }
-
+ /**
+ * Returns the preference key associated with this preference
+ *
+ * Note that this key is _usually_ a system property in and of itself, which is expected to hold
+ * the value of the preference. In this case though, this key *does not* hold the preference. It
+ * is only really used to tie this controller to the list preference defined in the XML file.
+ *
+ * @return the preference key associated with this preference
+ */
@Override
@Nullable
public String getPreferenceKey() {
return PREFERENCE_KEY;
}
+ /**
+ * Update the state of the preference based on what the user has selected
+ *
+ * This function is invoked when the user has selected a new value for this preference. The new
+ * value is the entry value at the index of the list the user has selected. This value will be
+ * one of the values from the array returned in getEntryValues(). Specifically, this array is
+ * set using R.array.bt_stack_log_level_values
+ *
+ * @param preference - the preference object to set the value of
+ * @param newValue - the value the user has selected, as an Object
+ * @return True when updated successfully
+ */
@Override
public boolean onPreferenceChange(@NonNull Preference preference, @NonNull Object newValue) {
- SystemProperties.set(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST, newValue.toString());
- SystemProperties.set(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY, newValue.toString());
- updateState(mPreference);
+ Log.v(TAG, "onPreferenceChange(pref=" + preference + "value=" + newValue.toString() + ")");
+ setBluetoothLogTag(newValue.toString());
+ setBluetoothLogLevelIndex(getBluetoothLogLevelIndex());
return true;
}
+ /**
+ * Refresh the state of this preference based on the state stored on the system
+ *
+ * Read the Bluetooth stack log level from the underlying system property/log tag, and map that
+ * level to the proper index in the values and entries array. Use those strings to set the value
+ * and summary of the preference.
+ *
+ * @param preference - the preference object to refresh the state of
+ */
@Override
public void updateState(@NonNull Preference preference) {
- final ListPreference listPreference = (ListPreference) preference;
- int index = getBluetoothLogLevelIndex();
- listPreference.setValue(mListValues[index]);
- listPreference.setSummary(mListEntries[index]);
+ Log.v(TAG, "updateState(pref=" + preference + "): refresh preference state");
+ setBluetoothLogLevelIndex(getBluetoothLogLevelIndex());
}
/**
- * Returns the current log level from Log.isLoggable().
+ * Notify this developer options preference of a change to developer options visibility
+ *
+ * We developer options are closed, we should clear out the value of this developer option
+ * preference and revert it back to the default state of INFO.
*/
- @VisibleForTesting
- public int getBluetoothLogLevelIndex() {
- if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.VERBOSE)) {
- return BTSTACK_LOG_MODE_VERBOSE_INDEX;
- } else if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.DEBUG)) {
- return BTSTACK_LOG_MODE_DEBUG_INDEX;
- } else if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.INFO)) {
- return BTSTACK_LOG_MODE_INFO_INDEX;
- } else if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.WARN)) {
- return BTSTACK_LOG_MODE_WARN_INDEX;
- } else if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.ERROR)) {
- return BTSTACK_LOG_MODE_ERROR_INDEX;
- }
- return BTSTACK_LOG_MODE_INFO_INDEX;
- }
-
@Override
protected void onDeveloperOptionsSwitchDisabled() {
super.onDeveloperOptionsSwitchDisabled();
- SystemProperties.set(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST, null);
- SystemProperties.set(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY, null);
- ((ListPreference) mPreference).setValue(mListValues[getDefaultModeIndex()]);
- ((ListPreference) mPreference).setSummary(mListEntries[getDefaultModeIndex()]);
+ Log.v(TAG, "onDeveloperOptionsSwitchDisabled(): Revert stack log to default");
+ setBluetoothLogTag(null);
+ setBluetoothLogLevelIndex(BT_LOG_LEVEL_DEFAULT_INDEX);
+ }
+
+ /**
+ * Set the system property values used by the Log framework to read the "bluetooth" log tag
+ *
+ * @param logLevel - the log level to set the Bluetooth stack minimum log level to
+ */
+ private void setBluetoothLogTag(@Nullable String logLevel) {
+ Log.i(TAG, "setBluetoothLogTag(logLevel=" + logLevel + "): Set properties for log tag");
+ SystemProperties.set(BT_LOG_LEVEL_PROP_PERSIST, logLevel);
+ SystemProperties.set(BT_LOG_LEVEL_PROP, logLevel);
+ }
+
+ /**
+ * Get the entry and value index corresponding to the current Bluetooth stack log level
+ *
+ * Since this preference uses an actual log tag and not a specific/private system property, we
+ * can read the value using the Log.isLoggable() function with our "bluetooth" log tag that
+ * represents the log level of the Bluetooth stack. This is safer than trying to replacate the
+ * logic used in the Log framework around the various persist, ro, and blank variants of the tag
+ *
+ * If no value is present, INFO is used.
+ *
+ * @return the entry/value index corresponding to the current log level of the tag "bluetooth"
+ */
+ @VisibleForTesting
+ public int getBluetoothLogLevelIndex() {
+ int level = BT_LOG_LEVEL_DEFAULT_INDEX;
+ if (Log.isLoggable(BT_LOG_TAG, Log.VERBOSE)) {
+ level = BT_LOG_LEVEL_VERBOSE_INDEX;
+ } else if (Log.isLoggable(BT_LOG_TAG, Log.DEBUG)) {
+ level = BT_LOG_LEVEL_DEBUG_INDEX;
+ } else if (Log.isLoggable(BT_LOG_TAG, Log.INFO)) {
+ level = BT_LOG_LEVEL_INFO_INDEX;
+ } else if (Log.isLoggable(BT_LOG_TAG, Log.WARN)) {
+ level = BT_LOG_LEVEL_WARN_INDEX;
+ } else if (Log.isLoggable(BT_LOG_TAG, Log.ERROR)) {
+ level = BT_LOG_LEVEL_ERROR_INDEX;
+ }
+ Log.v(TAG, "getBluetoothLogLevelIndex() -> " + level);
+ return level;
+ }
+
+ /**
+ * Set the current Bluetooth stack log level displayed in the list for this preference
+ *
+ * @param index - the index representing the log level choice of this preference
+ */
+ private void setBluetoothLogLevelIndex(int index) {
+ if (index < BT_LOG_LEVEL_VERBOSE_INDEX || index > BT_LOG_LEVEL_ERROR_INDEX) {
+ Log.e(TAG, "setBluetoothLogLevelIndex(index=" + index + "): Log level invalid");
+ return;
+ }
+
+ String value = mListValues[index];
+ String entryValue = mListEntries[index];
+
+ ListPreference preference = ((ListPreference) mPreference);
+ if (preference == null) {
+ Log.e(TAG, "setBluetoothLogLevelIndex(index=" + index + "): mPreference is null");
+ return;
+ }
+
+ preference.setValue(value);
+ preference.setSummary(entryValue);
+
+ Log.i(TAG, "setBluetoothLogLevelIndex(index=" + index
+ + "): Updated Bluetooth stack log level to value='" + value + "', entryValue='"
+ + entryValue + "'");
}
}
diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
index 7d15858..f121d0c 100644
--- a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
@@ -81,7 +81,10 @@
return mContext.getString(
com.android.settingslib.R.string.battery_info_status_not_charging);
}
- if (BatteryUtils.isBatteryDefenderOn(info)) {
+ if (BatteryUtils.isBatteryDefenderOn(info)
+ || FeatureFactory.getFeatureFactory()
+ .getPowerUsageFeatureProvider()
+ .isExtraDefend()) {
return mContext.getString(
com.android.settingslib.R.string.battery_info_status_charging_on_hold);
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
index bfa501c..f710c71 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
@@ -63,8 +63,8 @@
}
final String action = intent.getAction();
Log.d(TAG, "onReceive:" + action);
- if (com.android.settingslib.fuelgauge.BatteryUtils.isWorkProfile(context)) {
- Log.w(TAG, "do nothing for work profile action=" + action);
+ if (com.android.settingslib.fuelgauge.BatteryUtils.isAdditionalProfile(context)) {
+ Log.w(TAG, "do nothing for an additional profile action=" + action);
return;
}
DatabaseUtils.recordDateTime(context, action);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
index 095a65a..52010af 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
@@ -110,8 +110,8 @@
@Override
public boolean onCreate() {
- if (BatteryUtils.isWorkProfile(getContext())) {
- Log.w(TAG, "do not create provider for work profile");
+ if (BatteryUtils.isAdditionalProfile(getContext())) {
+ Log.w(TAG, "do not create provider for an additional profile");
return false;
}
mClock = Clock.systemUTC();
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
index b758df4..45d724f 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
@@ -54,8 +54,8 @@
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent == null ? "" : intent.getAction();
- if (BatteryUtils.isWorkProfile(context)) {
- Log.w(TAG, "do not start job for work profile action=" + action);
+ if (BatteryUtils.isAdditionalProfile(context)) {
+ Log.w(TAG, "do not start job for an additional profile action=" + action);
return;
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index 7620323..6feb815 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -70,6 +70,7 @@
/** Clear memory threshold for device booting phase. */
private static final long CLEAR_MEMORY_THRESHOLD_MS = Duration.ofMinutes(5).toMillis();
+
private static final long CLEAR_MEMORY_DELAYED_MS = Duration.ofSeconds(2).toMillis();
private static final long INVALID_TIMESTAMP = 0L;
@@ -527,9 +528,11 @@
return startCalendar.getTimeInMillis();
}
- /** Returns the context with profile parent identity when current user is work profile. */
+ /**
+ * Returns the context with profile parent identity when current user is an additional profile.
+ */
public static Context getParentContext(Context context) {
- if (com.android.settingslib.fuelgauge.BatteryUtils.isWorkProfile(context)) {
+ if (com.android.settingslib.fuelgauge.BatteryUtils.isAdditionalProfile(context)) {
try {
return context.createPackageContextAsUser(
/* packageName= */ context.getPackageName(),
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
index 5c73adb..982cf40 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
@@ -50,10 +50,10 @@
Log.w(TAG, "receive unexpected action=" + action);
return;
}
- if (BatteryUtils.isWorkProfile(context)) {
+ if (BatteryUtils.isAdditionalProfile(context)) {
BatteryUsageLogUtils.writeLog(
- context, Action.SCHEDULE_JOB, "do not refresh job for work profile");
- Log.w(TAG, "do not refresh job for work profile action=" + action);
+ context, Action.SCHEDULE_JOB, "do not refresh job for an additional profile");
+ Log.w(TAG, "do not refresh job for an additional profile action=" + action);
return;
}
BatteryUsageLogUtils.writeLog(context, Action.EXECUTE_JOB, "");
diff --git a/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
index 7e759ee..e829a3c 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
@@ -49,8 +49,8 @@
Log.w(TAG, "failed to dump BatteryUsage state: null application context");
return;
}
- if (BatteryUtils.isWorkProfile(context)) {
- Log.w(TAG, "ignore battery usage states dump in the work profile");
+ if (BatteryUtils.isAdditionalProfile(context)) {
+ Log.w(TAG, "ignore battery usage states dump in the additional profile");
return;
}
writer.println("dump BatteryUsage and AppUsage states:");
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index b4f13e8..d5d079e 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -492,9 +492,10 @@
: null;
updatePreferencesOrFinish(false /* isRecreatingActivity */);
if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getContext(),
- mBiometricsAuthSuccessful, mWaitingForConfirmation)) {
+ mBiometricsAuthSuccessful, mWaitingForConfirmation, mUserId)) {
mWaitingForConfirmation = true;
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+ Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+ mUserId);
}
} else if (requestCode == BIOMETRIC_AUTH_REQUEST) {
if (resultCode == Activity.RESULT_OK) {
diff --git a/tests/robotests/src/com/android/settings/MainClearTest.java b/tests/robotests/src/com/android/settings/MainClearTest.java
index 187fce1..26a430b 100644
--- a/tests/robotests/src/com/android/settings/MainClearTest.java
+++ b/tests/robotests/src/com/android/settings/MainClearTest.java
@@ -140,8 +140,8 @@
when(mScrollView.getChildCount()).thenReturn(1);
doReturn(mMockActivity).when(mMainClear).getActivity();
when(mMockActivity.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
- when(mBiometricManager.canAuthenticate(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ when(mBiometricManager.canAuthenticate(anyInt(),
+ eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
}
@@ -370,8 +370,8 @@
when(mContext.getResources()).thenReturn(mResources);
when(mMockActivity.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
when(mResources.getString(anyInt())).thenReturn(TEST_ACCOUNT_NAME);
- when(mBiometricManager.canAuthenticate(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ when(mBiometricManager.canAuthenticate(anyInt(),
+ eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
doReturn(true).when(mMainClear).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST));
doNothing().when(mMainClear).startActivityForResult(any(), anyInt());
diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java
index fd97b78..b36e9d6 100644
--- a/tests/robotests/src/com/android/settings/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/UtilsTest.java
@@ -81,6 +81,7 @@
import androidx.fragment.app.FragmentActivity;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.password.ConfirmDeviceCredentialActivity;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
@@ -532,31 +533,45 @@
when(mContext.getSystemService(BiometricManager.class)).thenReturn(null);
assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
false /* biometricsSuccessfullyAuthenticated */,
- false /* biometricsAuthenticationRequested */)).isFalse();
+ false /* biometricsAuthenticationRequested */, USER_ID)).isFalse();
}
@Test
@EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
public void testRequestBiometricAuthentication_biometricManagerReturnsSuccess_shouldReturnTrue() {
- when(mBiometricManager.canAuthenticate(
+ when(mBiometricManager.canAuthenticate(USER_ID,
BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
- boolean requestBiometricAuthenticationForMandatoryBiometrics =
+ final boolean requestBiometricAuthenticationForMandatoryBiometrics =
Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
- true /* biometricsSuccessfullyAuthenticated */,
- false /* biometricsAuthenticationRequested */);
- assertThat(requestBiometricAuthenticationForMandatoryBiometrics).isFalse();
+ false /* biometricsSuccessfullyAuthenticated */,
+ false /* biometricsAuthenticationRequested */, USER_ID);
+ assertThat(requestBiometricAuthenticationForMandatoryBiometrics).isTrue();
}
@Test
@EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
public void testRequestBiometricAuthentication_biometricManagerReturnsError_shouldReturnFalse() {
- when(mBiometricManager.canAuthenticate(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ when(mBiometricManager.canAuthenticate(anyInt(),
+ eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
false /* biometricsSuccessfullyAuthenticated */,
- false /* biometricsAuthenticationRequested */)).isFalse();
+ false /* biometricsAuthenticationRequested */, USER_ID)).isFalse();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
+ public void testRequestBiometricAuthentication_biometricManagerReturnsSuccessForDifferentUser_shouldReturnFalse() {
+ when(mBiometricManager.canAuthenticate(anyInt(),
+ eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
+ .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
+ when(mBiometricManager.canAuthenticate(0 /* userId */,
+ BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ .thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
+ assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
+ false /* biometricsSuccessfullyAuthenticated */,
+ false /* biometricsAuthenticationRequested */, USER_ID)).isFalse();
}
@Test
@@ -566,7 +581,7 @@
final int requestCode = 1;
final ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
- Utils.launchBiometricPromptForMandatoryBiometrics(mFragment, requestCode);
+ Utils.launchBiometricPromptForMandatoryBiometrics(mFragment, requestCode, USER_ID);
verify(mFragment).startActivityForResult(intentArgumentCaptor.capture(), eq(requestCode));
@@ -576,9 +591,12 @@
BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
assertThat(intent.getExtra(BIOMETRIC_PROMPT_NEGATIVE_BUTTON_TEXT)).isNotNull();
assertThat(intent.getExtra(KeyguardManager.EXTRA_DESCRIPTION)).isNotNull();
+ assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, false))
+ .isTrue();
+ assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0)).isEqualTo(USER_ID);
assertThat(intent.getComponent().getPackageName()).isEqualTo(SETTINGS_PACKAGE_NAME);
assertThat(intent.getComponent().getClassName()).isEqualTo(
- ConfirmDeviceCredentialActivity.class.getName());
+ ConfirmDeviceCredentialActivity.InternalActivity.class.getName());
}
private void setUpForConfirmCredentialString(boolean isEffectiveUserManagedProfile) {
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
index 1463cd0..cb2429c 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
@@ -26,11 +26,9 @@
import static java.util.Collections.singletonList;
import android.accessibilityservice.AccessibilityServiceInfo;
-import android.accessibilityservice.AccessibilityShortcutInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -110,9 +108,7 @@
private final Context mContext = ApplicationProvider.getApplicationContext();
@Spy
private final AccessibilityServiceInfo mServiceInfo = getMockAccessibilityServiceInfo(
- PACKAGE_NAME, CLASS_NAME);
- @Mock
- private AccessibilityShortcutInfo mShortcutInfo;
+ new ComponentName(PACKAGE_NAME, CLASS_NAME));
private ShadowAccessibilityManager mShadowAccessibilityManager;
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
@@ -125,7 +121,6 @@
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(new ArrayList<>());
mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat);
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
- setMockAccessibilityShortcutInfo(mShortcutInfo);
Intent intent = new Intent();
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT,
@@ -398,14 +393,25 @@
public void testAccessibilityMenuInSystem_IncludedInInteractionControl() {
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
List.of(getMockAccessibilityServiceInfo(
- AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM)));
+ AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM,
+ /*isSystemApp=*/true)));
setupFragment();
- final RestrictedPreference pref = mFragment.getPreferenceScreen().findPreference(
- AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM.flattenToString());
- final String prefCategory = mFragment.mServicePreferenceToPreferenceCategoryMap.get(
- pref).getKey();
- assertThat(prefCategory).isEqualTo(AccessibilitySettings.CATEGORY_INTERACTION_CONTROL);
+ assertThat(getPreferenceCategory(AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM))
+ .isEqualTo(AccessibilitySettings.CATEGORY_INTERACTION_CONTROL);
+ }
+
+ @Test
+ @EnableFlags(com.android.settings.accessibility.Flags.FLAG_CHECK_PREBUNDLED_IS_PREINSTALLED)
+ public void testNonPreinstalledApp_IncludedInDownloadedCategory() {
+ mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
+ List.of(getMockAccessibilityServiceInfo(
+ AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM,
+ /*isSystemApp=*/false)));
+ setupFragment();
+
+ assertThat(getPreferenceCategory(AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM))
+ .isEqualTo(AccessibilitySettings.CATEGORY_DOWNLOADED_SERVICES);
}
@Test
@@ -418,13 +424,20 @@
assertThat(pref).isNull();
}
- private AccessibilityServiceInfo getMockAccessibilityServiceInfo(String packageName,
- String className) {
- return getMockAccessibilityServiceInfo(new ComponentName(packageName, className));
+ private String getPreferenceCategory(ComponentName componentName) {
+ return mFragment.mServicePreferenceToPreferenceCategoryMap.get(
+ mFragment.getPreferenceScreen().findPreference(
+ componentName.flattenToString())).getKey();
}
private AccessibilityServiceInfo getMockAccessibilityServiceInfo(ComponentName componentName) {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
+ return getMockAccessibilityServiceInfo(componentName, true);
+ }
+
+ private AccessibilityServiceInfo getMockAccessibilityServiceInfo(ComponentName componentName,
+ boolean isSystemApp) {
+ final ApplicationInfo applicationInfo = Mockito.mock(ApplicationInfo.class);
+ when(applicationInfo.isSystemApp()).thenReturn(isSystemApp);
final ServiceInfo serviceInfo = new ServiceInfo();
applicationInfo.packageName = componentName.getPackageName();
serviceInfo.packageName = componentName.getPackageName();
@@ -445,16 +458,6 @@
return null;
}
- private void setMockAccessibilityShortcutInfo(AccessibilityShortcutInfo mockInfo) {
- final ActivityInfo activityInfo = Mockito.mock(ActivityInfo.class);
- activityInfo.applicationInfo = new ApplicationInfo();
- when(mockInfo.getActivityInfo()).thenReturn(activityInfo);
- when(activityInfo.loadLabel(any())).thenReturn(DEFAULT_LABEL);
- when(mockInfo.loadSummary(any())).thenReturn(DEFAULT_SUMMARY);
- when(mockInfo.loadDescription(any())).thenReturn(DEFAULT_DESCRIPTION);
- when(mockInfo.getComponentName()).thenReturn(COMPONENT_NAME);
- }
-
private void setInvisibleToggleFragmentType(AccessibilityServiceInfo info) {
info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R;
info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
diff --git a/tests/robotests/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceControllerTest.java
index 98ed442..5fd11f9 100644
--- a/tests/robotests/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceControllerTest.java
@@ -16,38 +16,39 @@
package com.android.settings.accessibility;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
import android.content.ContentResolver;
import android.content.Context;
+import android.os.Looper;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.server.accessibility.Flags;
import com.android.settings.widget.SeekBarPreference;
+import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link DaltonizerSaturationSeekbarPreferenceController}. */
@@ -60,8 +61,9 @@
private int mOriginalSaturationLevel = -1;
private PreferenceScreen mScreen;
+ private LifecycleOwner mLifecycleOwner;
+ private Lifecycle mLifecycle;
- @Mock
private SeekBarPreference mPreference;
@Rule
@@ -69,7 +71,6 @@
@Before
public void setup() {
- MockitoAnnotations.initMocks(this);
Context context = ApplicationProvider.getApplicationContext();
mContentResolver = context.getContentResolver();
mOriginalSaturationLevel = Settings.Secure.getInt(
@@ -77,10 +78,13 @@
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
7);
- mScreen = spy(new PreferenceScreen(context, /* attrs= */ null));
- when(mScreen.findPreference(ToggleDaltonizerPreferenceFragment.KEY_SATURATION))
- .thenReturn(mPreference);
+ mPreference = new SeekBarPreference(context);
+ mPreference.setKey(ToggleDaltonizerPreferenceFragment.KEY_SATURATION);
+ mScreen = new PreferenceManager(context).createPreferenceScreen(context);
+ mScreen.addPreference(mPreference);
+ mLifecycleOwner = () -> mLifecycle;
+ mLifecycle = new Lifecycle(mLifecycleOwner);
mController = new DaltonizerSaturationSeekbarPreferenceController(
context,
ToggleDaltonizerPreferenceFragment.KEY_SATURATION);
@@ -94,6 +98,12 @@
mOriginalSaturationLevel);
}
+ @Test
+ public void constructor_defaultValuesMatch() {
+ assertThat(mController.getSliderPosition()).isEqualTo(7);
+ assertThat(mController.getMax()).isEqualTo(10);
+ assertThat(mController.getMin()).isEqualTo(1);
+ }
@Test
@DisableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
@@ -103,28 +113,72 @@
@Test
@EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
- public void getAvailabilityStatus_flagEnabled_available() {
+ public void getAvailabilityStatus_flagEnabledProtanEnabled_available() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
- public void constructor_defaultValuesMatch() {
- assertThat(mController.getSliderPosition()).isEqualTo(7);
- assertThat(mController.getMax()).isEqualTo(10);
- assertThat(mController.getMin()).isEqualTo(0);
+ @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+ public void getAvailabilityStatus_flagEnabledDeutranEnabled_available() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 12);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
- public void displayPreference_enabled_visible() {
+ public void getAvailabilityStatus_flagEnabledTritanEnabled_available() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 13);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+ public void getAvailabilityStatus_flagEnabledGrayScale_disabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 0);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+ public void getAvailabilityStatus_flagEnabledColorCorrectionDisabled_disabled() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 11);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+ public void getAvailabilityStatus_flagEnabledColorCorrectionDisabledGrayScale_disabled() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 0);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+ public void displayPreference_flagEnabledColorCorrectionEnabled_enabledWithDefaultValues() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
mController.displayPreference(mScreen);
- verify(mPreference).setMax(eq(10));
- verify(mPreference).setMin(eq(0));
- verify(mPreference).setProgress(eq(7));
- verify(mPreference).setContinuousUpdates(eq(true));
- verify(mPreference).setOnPreferenceChangeListener(eq(mController));
- verify(mPreference).setVisible(eq(true));
+ assertThat(mPreference.isEnabled()).isTrue();
+ assertThat(mPreference.getMax()).isEqualTo(10);
+ assertThat(mPreference.getMin()).isEqualTo(1);
+ assertThat(mPreference.getProgress()).isEqualTo(7);
+ assertThat(mPreference.isVisible()).isTrue();
+ assertThat(mPreference.getOnPreferenceChangeListener()).isEqualTo(mController);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+ public void displayPreference_flagEnabledColorCorrectionDisabled_disabledWithDefaultValues() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 11);
+ mController.displayPreference(mScreen);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ assertThat(mPreference.getMax()).isEqualTo(10);
+ assertThat(mPreference.getMin()).isEqualTo(1);
+ assertThat(mPreference.getProgress()).isEqualTo(7);
+ assertThat(mPreference.isVisible()).isTrue();
+ assertThat(mPreference.getOnPreferenceChangeListener()).isEqualTo(mController);
}
@Test
@@ -132,12 +186,8 @@
public void displayPreference_disabled_notVisible() {
mController.displayPreference(mScreen);
- verify(mPreference).setMax(eq(10));
- verify(mPreference).setMin(eq(0));
- verify(mPreference).setProgress(eq(7));
- verify(mPreference).setContinuousUpdates(eq(true));
- verify(mPreference, never()).setOnPreferenceChangeListener(any());
- verify(mPreference).setVisible(eq(false));
+ assertThat(mPreference.isVisible()).isFalse();
+ assertThat(mPreference.getOnPreferenceChangeListener()).isNull();
}
@Test
@@ -153,13 +203,13 @@
@Test
public void setSliderPosition_min_secureSettingsUpdated() {
- var isSliderSet = mController.setSliderPosition(0);
+ var isSliderSet = mController.setSliderPosition(1);
assertThat(isSliderSet).isTrue();
assertThat(Settings.Secure.getInt(
mContentResolver,
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
- 7)).isEqualTo(0);
+ 7)).isEqualTo(1);
}
@Test
@@ -194,4 +244,140 @@
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
7)).isEqualTo(7);
}
+
+ @Test
+ public void updateState_enabledProtan_preferenceEnabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void updateState_enabledDeuteran_preferenceEnabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 12);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void updateState_enabledTritan_preferenceEnabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 13);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void updateState_disabledGrayScale_preferenceDisabled() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 0);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void updateState_nullPreference_noError() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 0);
+
+ mController.updateState(null);
+ }
+
+ @Test
+ public void updateState_enabledGrayScale_preferenceDisabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 0);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void onResume_daltonizerEnabledAfterResumed_preferenceEnabled() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 11);
+ mController.displayPreference(mScreen);
+ assertThat(mPreference.isEnabled()).isFalse();
+
+ mLifecycle.addObserver(mController);
+ mLifecycle.handleLifecycleEvent(ON_RESUME);
+
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+ 1);
+ shadowOf(Looper.getMainLooper()).idle();
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void onResume_daltonizerDisabledAfterResumed_preferenceDisabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
+ mController.displayPreference(mScreen);
+ assertThat(mPreference.isEnabled()).isTrue();
+
+ mLifecycle.addObserver(mController);
+ mLifecycle.handleLifecycleEvent(ON_RESUME);
+
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+ 0);
+ shadowOf(Looper.getMainLooper()).idle();
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void onResume_daltonizerGrayScaledAfterResumed_preferenceDisabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
+ mController.displayPreference(mScreen);
+ assertThat(mPreference.isEnabled()).isTrue();
+
+ mLifecycle.addObserver(mController);
+ mLifecycle.handleLifecycleEvent(ON_RESUME);
+
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+ 0);
+ shadowOf(Looper.getMainLooper()).idle();
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void onStop_daltonizerEnabledAfterOnStop_preferenceNotChanged() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 11);
+ mController.displayPreference(mScreen);
+ assertThat(mPreference.isEnabled()).isFalse();
+
+ mLifecycle.addObserver(mController);
+ mLifecycle.handleLifecycleEvent(ON_STOP);
+
+ // enabled.
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+ 1);
+ shadowOf(Looper.getMainLooper()).idle();
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ private void setDaltonizerMode(int enabled, int mode) {
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+ enabled);
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+ mode);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java
index a775731..4f8860e 100644
--- a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java
@@ -127,8 +127,8 @@
mFragment = spy(new TestCombinedBiometricProfileSettings(mContext));
doReturn(mActivity).when(mFragment).getActivity();
doReturn(mBiometricManager).when(mActivity).getSystemService(BiometricManager.class);
- when(mBiometricManager.canAuthenticate(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ when(mBiometricManager.canAuthenticate(anyInt(),
+ eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
ReflectionHelpers.setField(mFragment, "mDashboardFeatureProvider",
@@ -181,8 +181,8 @@
public void testLaunchBiometricPrompt_onCreateFragment() {
ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
doNothing().when(mFragment).startActivityForResult(any(), anyInt());
- when(mBiometricManager.canAuthenticate(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ when(mBiometricManager.canAuthenticate(anyInt(),
+ eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
mFragment.onAttach(mContext);
@@ -193,7 +193,7 @@
Intent intent = intentArgumentCaptor.getValue();
assertThat(intent.getComponent().getClassName()).isEqualTo(
- ConfirmDeviceCredentialActivity.class.getName());
+ ConfirmDeviceCredentialActivity.InternalActivity.class.getName());
}
@Test
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
index a34b6de..29b2961 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
@@ -176,7 +176,7 @@
Intent intent = intentArgumentCaptor.getValue();
assertThat(intent.getComponent().getClassName()).isEqualTo(
- ConfirmDeviceCredentialActivity.class.getName());
+ ConfirmDeviceCredentialActivity.InternalActivity.class.getName());
}
// Test the case when FingerprintAuthenticateSidecar receives an error callback from the
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceTest.java
index 13e2a9d..be62414 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceTest.java
@@ -117,6 +117,7 @@
assertThat(shareButton.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(shareButton.getDrawable()).isNotNull();
assertThat(shareButton.hasOnClickListeners()).isTrue();
+ assertThat(shareButton.getContentDescription()).isNotNull();
assertThat(divider).isNotNull();
assertThat(divider.getVisibility()).isEqualTo(View.VISIBLE);
diff --git a/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
index bd005b3..978380e 100644
--- a/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
@@ -16,8 +16,9 @@
package com.android.settings.development;
-import static com.android.settings.development.FreeformWindowsPreferenceController
- .SETTING_VALUE_OFF;
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+
+import static com.android.settings.development.FreeformWindowsPreferenceController.SETTING_VALUE_OFF;
import static com.android.settings.development.FreeformWindowsPreferenceController.SETTING_VALUE_ON;
import static com.google.common.truth.Truth.assertThat;
@@ -29,6 +30,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.provider.Settings;
import androidx.fragment.app.FragmentActivity;
@@ -43,7 +45,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@@ -52,9 +53,10 @@
})
public class FreeformWindowsPreferenceControllerTest {
- private static final String ENG_BUILD_TYPE = "eng";
- private static final String USER_BUILD_TYPE = "user";
-
+ @Mock
+ Context mContext;
+ @Mock
+ private PackageManager mPackageManager;
@Mock
private SwitchPreference mPreference;
@Mock
@@ -68,33 +70,33 @@
@Mock
private FragmentTransaction mTransaction;
- private Context mContext;
private FreeformWindowsPreferenceController mController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
doReturn(mTransaction).when(mFragmentManager).beginTransaction();
doReturn(mFragmentManager).when(mActivity).getSupportFragmentManager();
doReturn(mActivity).when(mFragment).getActivity();
mController = new FreeformWindowsPreferenceController(mContext, mFragment);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
mController.displayPreference(mScreen);
}
@Test
- public void isAvailable_engBuild_shouldBeTrue() {
+ public void isAvailable_deviceHasFreeformWindowSystemFeature_returnsFalse() {
mController = spy(mController);
- doReturn(ENG_BUILD_TYPE).when(mController).getBuildType();
+ when(mPackageManager.hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)).thenReturn(true);
- assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.isAvailable()).isFalse();
}
@Test
- public void isAvailable_userBuild_shouldBeTrue() {
+ public void isAvailable_deviceDoesNotHaveFreeformWindowSystemFeature_returnsTrue() {
mController = spy(mController);
- doReturn(USER_BUILD_TYPE).when(mController).getBuildType();
+ when(mPackageManager.hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)).thenReturn(
+ false);
assertThat(mController.isAvailable()).isTrue();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
index b949a3e..fdb075d 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
@@ -389,6 +389,28 @@
verify(mBatteryUsageProgressBarPref).setBottomSummary(expectedChargingString);
}
+ @Test
+ public void updateBatteryStatus_dockDefend_chargingOnHold() {
+ var expected = "Charging on hold";
+ mBatteryInfo.isBatteryDefender = false;
+ when(mFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
+
+ mController.updateBatteryStatus(/* label= */ null, mBatteryInfo);
+
+ verify(mBatteryUsageProgressBarPref).setBottomSummary(expected);
+ }
+
+ @Test
+ public void updateBatteryStatus_batteryDefender_chargingOnHold() {
+ var expected = "Charging on hold";
+ mBatteryInfo.isBatteryDefender = true;
+ when(mFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
+
+ mController.updateBatteryStatus(/* label= */ null, mBatteryInfo);
+
+ verify(mBatteryUsageProgressBarPref).setBottomSummary(expected);
+ }
+
private BatteryInfo arrangeUpdateBatteryStatusTestWithRemainingLabel(
String remainingLabel,
String statusLabel,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
index af0cb91..63d44d0 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
@@ -28,9 +28,9 @@
import android.content.pm.PackageManager;
import android.os.BatteryManager;
import android.os.SystemClock;
+import android.os.UserManager;
import android.text.format.DateUtils;
-import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
@@ -49,6 +49,7 @@
private FakeFeatureFactory mFakeFeatureFactory;
@Mock private PackageManager mPackageManager;
+ @Mock private UserManager mUserManager;
@Before
public void setUp() {
@@ -57,6 +58,7 @@
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mBatteryUsageBroadcastReceiver = new BatteryUsageBroadcastReceiver();
doReturn(mPackageManager).when(mContext).getPackageManager();
+ doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
DatabaseUtils.getSharedPreferences(mContext).edit().clear().apply();
}
@@ -69,7 +71,17 @@
@Test
public void onReceive_workProfile_doNothing() {
- BatteryTestUtils.setWorkProfile(mContext);
+ doReturn(true).when(mUserManager).isManagedProfile();
+
+ mBatteryUsageBroadcastReceiver.onReceive(
+ mContext, new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING));
+
+ assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse();
+ }
+
+ @Test
+ public void onReceive_privateProfile_doNothing() {
+ doReturn(true).when(mUserManager).isPrivateProfile();
mBatteryUsageBroadcastReceiver.onReceive(
mContext, new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING));
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
index 950f828..ac711a4 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
@@ -19,12 +19,16 @@
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.UserManager;
import androidx.test.core.app.ApplicationProvider;
@@ -39,6 +43,8 @@
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 java.time.Duration;
@@ -62,9 +68,14 @@
private Context mContext;
private BatteryUsageContentProvider mProvider;
+ @Mock
+ private UserManager mUserManager;
+
@Before
public void setUp() {
- mContext = ApplicationProvider.getApplicationContext();
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
mProvider = new BatteryUsageContentProvider();
mProvider.attachInfo(mContext, /* info= */ null);
BatteryTestUtils.setUpBatteryStateDatabase(mContext);
@@ -77,7 +88,13 @@
@Test
public void onCreate_withWorkProfileMode_returnsFalse() {
- BatteryTestUtils.setWorkProfile(mContext);
+ doReturn(true).when(mUserManager).isManagedProfile();
+ assertThat(mProvider.onCreate()).isFalse();
+ }
+
+ @Test
+ public void onCreate_withPrivateProfileMode_returnsFalse() {
+ doReturn(true).when(mUserManager).isPrivateProfile();
assertThat(mProvider.onCreate()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java
index 704637f..f318a2b 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java
@@ -18,6 +18,9 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.app.AlarmManager;
@@ -26,6 +29,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.os.UserManager;
import androidx.test.core.app.ApplicationProvider;
@@ -37,6 +41,8 @@
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.Shadows;
import org.robolectric.shadows.ShadowAlarmManager;
@@ -55,10 +61,15 @@
private ShadowAlarmManager mShadowAlarmManager;
private PeriodicJobManager mPeriodicJobManager;
+ @Mock
+ private UserManager mUserManager;
+
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
- mContext = ApplicationProvider.getApplicationContext();
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
mPeriodicJobManager = PeriodicJobManager.getInstance(mContext);
mShadowAlarmManager = shadowOf(mContext.getSystemService(AlarmManager.class));
mReceiver = new BootBroadcastReceiver();
@@ -78,7 +89,15 @@
@Test
public void onReceive_withWorkProfile_notRefreshesJob() {
- BatteryTestUtils.setWorkProfile(mContext);
+ doReturn(true).when(mUserManager).isManagedProfile();
+ mReceiver.onReceive(mContext, new Intent(Intent.ACTION_BOOT_COMPLETED));
+
+ assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
+ }
+
+ @Test
+ public void onReceive_withPrivateProfile_notRefreshesJob() {
+ doReturn(true).when(mUserManager).isPrivateProfile();
mReceiver.onReceive(mContext, new Intent(Intent.ACTION_BOOT_COMPLETED));
assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
index d89e61b..2fda277 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
@@ -47,7 +47,6 @@
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
-import com.android.settings.testutils.BatteryTestUtils;
import org.junit.Before;
import org.junit.Test;
@@ -451,6 +450,26 @@
}
@Test
+ public void getHistoryMap_withPrivateProfile_returnExpectedMap()
+ throws PackageManager.NameNotFoundException {
+ doReturn("com.fake.package").when(mContext).getPackageName();
+ doReturn(mMockContext)
+ .when(mContext)
+ .createPackageContextAsUser("com.fake.package", /* flags= */ 0, UserHandle.OWNER);
+ doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+ doReturn(UserHandle.CURRENT).when(mContext).getUser();
+ doReturn(true).when(mUserManager).isPrivateProfile();
+ doReturn(UserHandle.SYSTEM).when(mUserManager).getProfileParent(UserHandle.CURRENT);
+
+ DatabaseUtils.sFakeSupplier = () -> getMatrixCursor();
+
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistMap =
+ DatabaseUtils.getHistoryMapSinceQueryTimestamp(mContext, 0);
+
+ assertThat(batteryHistMap).isEmpty();
+ }
+
+ @Test
public void removeUsageSource_hasNoData() {
DatabaseUtils.removeUsageSource(mContext);
assertThat(
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiverTest.java
index d111de2..ea3c04c 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiverTest.java
@@ -18,11 +18,15 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.app.AlarmManager;
import android.content.Context;
import android.content.Intent;
+import android.os.UserManager;
import androidx.test.core.app.ApplicationProvider;
@@ -34,6 +38,8 @@
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.shadows.ShadowAlarmManager;
@@ -53,12 +59,17 @@
private PeriodicJobManager mPeriodicJobManager;
private ShadowAlarmManager mShadowAlarmManager;
+ @Mock
+ private UserManager mUserManager;
+
@Before
public void setUp() {
- mContext = ApplicationProvider.getApplicationContext();
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
mPeriodicJobManager = PeriodicJobManager.getInstance(mContext);
mShadowAlarmManager = shadowOf(mContext.getSystemService(AlarmManager.class));
mReceiver = new PeriodicJobReceiver();
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
// Inserts fake data into database for testing.
final BatteryStateDatabase database = BatteryTestUtils.setUpBatteryStateDatabase(mContext);
@@ -114,7 +125,14 @@
@Test
public void onReceive_inWorkProfileMode_notRefreshesJob() {
- BatteryTestUtils.setWorkProfile(mContext);
+ doReturn(true).when(mUserManager).isManagedProfile();
+ mReceiver.onReceive(mContext, JOB_UPDATE_INTENT);
+ assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
+ }
+
+ @Test
+ public void onReceive_inPrivateProfileMode_notRefreshesJob() {
+ doReturn(true).when(mUserManager).isPrivateProfile();
mReceiver.onReceive(mContext, JOB_UPDATE_INTENT);
assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java
index d998106..0dd18c5 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java
@@ -18,7 +18,11 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
import android.content.Context;
+import android.os.UserManager;
import androidx.test.core.app.ApplicationProvider;
@@ -27,6 +31,8 @@
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 java.io.FileDescriptor;
@@ -46,11 +52,17 @@
private StringWriter mStringWriter;
private BugReportContentProvider mBugReportContentProvider;
+ @Mock
+ private UserManager mUserManager;
+
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
mStringWriter = new StringWriter();
mPrintWriter = new PrintWriter(mStringWriter);
- mContext = ApplicationProvider.getApplicationContext();
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ doReturn(mContext).when(mContext).getApplicationContext();
+ doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
mBugReportContentProvider = new BugReportContentProvider();
mBugReportContentProvider.attachInfo(mContext, /* info= */ null);
// Inserts fake data into database for testing.
@@ -77,7 +89,14 @@
@Test
public void dump_inWorkProfileMode_notDumpsBatteryUsageData() {
- BatteryTestUtils.setWorkProfile(mContext);
+ doReturn(true).when(mUserManager).isManagedProfile();
+ mBugReportContentProvider.dump(FileDescriptor.out, mPrintWriter, new String[] {});
+ assertThat(mStringWriter.toString()).isEmpty();
+ }
+
+ @Test
+ public void dump_inPrivateProfileMode_notDumpsBatteryUsageData() {
+ doReturn(true).when(mUserManager).isPrivateProfile();
mBugReportContentProvider.dump(FileDescriptor.out, mPrintWriter, new String[] {});
assertThat(mStringWriter.toString()).isEmpty();
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
index 64a5f11..c52fe2f 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
@@ -19,9 +19,8 @@
import android.Manifest;
import android.content.Context;
import android.content.pm.CrossProfileApps;
-import android.content.pm.ICrossProfileApps;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageInfo;
import androidx.annotation.NonNull;
@@ -35,15 +34,7 @@
@Implements(CrossProfileApps.class)
public class ShadowCrossProfileApps extends org.robolectric.shadows.ShadowCrossProfileApps {
private static final Set<String> configurableInteractAcrossProfilePackages = new HashSet<>();
- private Context mContext;
- private PackageManager mPackageManager;
- @Implementation
- protected void __constructor__(Context context, ICrossProfileApps service) {
- super.__constructor__(context, service);
- this.mContext = context;
- this.mPackageManager = context.getPackageManager();
- }
public void addCrossProfilePackage(String packageName) {
configurableInteractAcrossProfilePackages.add(packageName);
}
@@ -57,7 +48,9 @@
protected boolean canUserAttemptToConfigureInteractAcrossProfiles(@NonNull String packageName) {
PackageInfo packageInfo;
try {
- packageInfo = mPackageManager.getPackageInfo(packageName, /* flags= */ 0);
+ packageInfo = getContext().getPackageManager().getPackageInfo(
+ packageName,
+ /* flags= */ 0);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
diff --git a/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java b/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java
index ab1f469..2aa10bb 100644
--- a/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java
@@ -16,13 +16,9 @@
package com.android.settings.development.bluetooth;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_VERBOSE_INDEX;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_DEBUG_INDEX;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_INFO_INDEX;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_WARN_INDEX;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_ERROR_INDEX;
+import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BT_LOG_LEVEL_DEFAULT_INDEX;
+import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BT_LOG_LEVEL_PROP;
+import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BT_LOG_LEVEL_PROP_PERSIST;
import static com.google.common.truth.Truth.assertThat;
@@ -37,18 +33,21 @@
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
-@Ignore("b/339148064")
public class BluetoothStackLogPreferenceControllerTest {
- private static final String TAG = "BluetoothStackLogPreferenceControllerTest";
+ private static final String COM_ANDROID_SETTINGS = "com.android.settings";
+ private static final String TYPE_ARRAY = "array";
- @Mock private Context mContext;
+ private static final String XML_DEFINED_PREFERENCE_KEY = "bt_stack_log_level";
+ private static final String XML_DEFINED_ENTRIES_RESOURCE = "bt_stack_log_level_entries";
+ private static final String XML_DEFINED_VALUES_RESOURCE = "bt_stack_log_level_values";
+
+ private static final String PROPERTY_CLEARED = "";
+
+ private Context mContext;
private ListPreference mPreference;
private PreferenceManager mPreferenceManager;
@@ -61,7 +60,6 @@
@Before
public void setup() {
- MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
if (Looper.myLooper() == null) {
@@ -71,12 +69,11 @@
mPreferenceManager = new PreferenceManager(mContext);
mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
mPreference = new ListPreference(mContext);
-
mController = new BluetoothStackLogPreferenceController(mContext);
mPreference.setKey(mController.getPreferenceKey());
- mPreference.setEntries(com.android.settings.R.array.bt_stack_log_level_entries);
- mPreference.setEntryValues(com.android.settings.R.array.bt_stack_log_level_values);
+ mPreference.setEntries(getStringArrayResourceId(XML_DEFINED_ENTRIES_RESOURCE));
+ mPreference.setEntryValues(getStringArrayResourceId(XML_DEFINED_VALUES_RESOURCE));
mPreferenceScreen.addPreference(mPreference);
mController.displayPreference(mPreferenceScreen);
@@ -86,134 +83,109 @@
}
/**
- * Test that default log level is set to INFO
+ * Get the resource ID associated with a resource name
+ *
+ * This looks up the resource id by name using our device's context. This way, we can avoid
+ * hardcoding a resource ID or value from the R class which may not match the resource IDs on
+ * the device under test.
+ *
+ * Usage: int valuesResId = getStringArrayResource("bt_stack_log_level_values");
+ * Usage: int entriesResId = getStringArrayResource("bt_stack_log_level_entries");
+ *
+ * @param res - The resource name to look up
+ * @return The integer resource ID corresponding to the given resource name
*/
- @Test
- public void verifyDefaultState_enablesDefaultLogLevelEntriesAndValuesSameSize() {
- mController.onPreferenceChange(mPreference, mController.getDefaultModeIndex());
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
- [BTSTACK_LOG_MODE_INFO_INDEX].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
- [BTSTACK_LOG_MODE_INFO_INDEX].toString());
+ public int getStringArrayResourceId(String res) {
+ return mContext.getResources().getIdentifier(res, TYPE_ARRAY, COM_ANDROID_SETTINGS);
}
/**
- * Test that log level is changed to VERBOSE when VERBOSE is selected
+ * Test that, for each possible value a user can select, our controller properly handles the
+ * value to update the underlying system property _and_ set the UI entry to the proper value.
*/
@Test
- public void onPreferenceChanged_enableBluetoothStackVerboseLogLevel() {
- mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_VERBOSE_INDEX]
- .toString());
+ public void onPreferenceChange_withEachValue_uiSetProperlyAndAllValuesWrittenToProperties() {
+ for (int index = 0; index < mListValues.length; index++) {
+ String value = mListValues[index].toString();
+ String entry = mListEntries[index].toString();
- final String persistedLogLevel = SystemProperties.get(
- BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
- final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
- assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_VERBOSE_INDEX]
- .toString());
- assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_VERBOSE_INDEX].toString());
+ mController.onPreferenceChange(mPreference, value);
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
- [BTSTACK_LOG_MODE_VERBOSE_INDEX].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
- [BTSTACK_LOG_MODE_VERBOSE_INDEX].toString());
+ final String persistedLogLevel = SystemProperties.get(BT_LOG_LEVEL_PROP_PERSIST);
+ final String logLevel = SystemProperties.get(BT_LOG_LEVEL_PROP);
+ final String currentValue = mPreference.getValue().toString();
+ final String currentEntry = mPreference.getEntry().toString();
+ final String currentSummary = mPreference.getSummary().toString();
+ final int currentIndex = mPreference.findIndexOfValue(currentValue);
+
+ assertThat(persistedLogLevel).isEqualTo(value);
+ assertThat(logLevel).isEqualTo(value);
+ assertThat(currentIndex).isEqualTo(index);
+ assertThat(currentValue).isEqualTo(value);
+ assertThat(currentEntry).isEqualTo(entry);
+ assertThat(currentSummary).isEqualTo(entry);
+ }
}
/**
- * Test that log level is changed to DEBUG when DEBUG is selected
+ * Test that, for each possible log tag log level value, our controller properly handles the
+ * value to set the UI entry to the proper value.
*/
@Test
- public void onPreferenceChanged_enableBluetoothStackDebugLogLevel() {
- mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_DEBUG_INDEX]
- .toString());
+ public void updateState_withEachValue_uiSetProperly() {
+ for (int index = 0; index < mListValues.length; index++) {
+ String value = mListValues[index].toString();
+ String entry = mListEntries[index].toString();
- final String persistedLogLevel = SystemProperties.get(
- BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
- final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
- assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_DEBUG_INDEX]
- .toString());
- assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_DEBUG_INDEX].toString());
+ SystemProperties.set(BT_LOG_LEVEL_PROP_PERSIST, value);
+ SystemProperties.set(BT_LOG_LEVEL_PROP, value);
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
- [BTSTACK_LOG_MODE_DEBUG_INDEX].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
- [BTSTACK_LOG_MODE_DEBUG_INDEX].toString());
+ mController.updateState(mPreference);
+
+ final String currentValue = mPreference.getValue().toString();
+ final String currentEntry = mPreference.getEntry().toString();
+ final String currentSummary = mPreference.getSummary().toString();
+ final int currentIndex = mPreference.findIndexOfValue(currentValue);
+
+ assertThat(currentIndex).isEqualTo(index);
+ assertThat(currentValue).isEqualTo(value);
+ assertThat(currentEntry).isEqualTo(entry);
+ assertThat(currentSummary).isEqualTo(entry);
+ }
}
/**
- * Test that log level is changed to INFO when INFO is selected
+ * Test that our controller reverts the log level back to a missing/default value when we're
+ * notified that Developer Options has been disabled.
*/
@Test
- public void onPreferenceChanged_enableBluetoothStackInfoLogLevel() {
- mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_INFO_INDEX]
- .toString());
+ public void onDeveloperOptionsSwitchDisabled_preferenceSetToDefault() {
+ mController.onDeveloperOptionsSwitchDisabled();
- final String persistedLogLevel = SystemProperties.get(
- BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
- final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
- assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_INFO_INDEX]
- .toString());
- assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_INFO_INDEX].toString());
+ final String defaultEntry = mListEntries[BT_LOG_LEVEL_DEFAULT_INDEX].toString();
+ final String defaultValue = mListValues[BT_LOG_LEVEL_DEFAULT_INDEX].toString();
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
- [BTSTACK_LOG_MODE_INFO_INDEX].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
- [BTSTACK_LOG_MODE_INFO_INDEX].toString());
+ final String persistedLogLevel = SystemProperties.get(BT_LOG_LEVEL_PROP_PERSIST);
+ final String logLevel = SystemProperties.get(BT_LOG_LEVEL_PROP);
+ final String currentValue = mPreference.getValue().toString();
+ final String currentEntry = mPreference.getEntry().toString();
+ final String currentSummary = mPreference.getSummary().toString();
+ final int currentIndex = mPreference.findIndexOfValue(currentValue);
+
+ assertThat(persistedLogLevel).isEqualTo(PROPERTY_CLEARED);
+ assertThat(logLevel).isEqualTo(PROPERTY_CLEARED);
+ assertThat(currentIndex).isEqualTo(BT_LOG_LEVEL_DEFAULT_INDEX);
+ assertThat(currentValue).isEqualTo(defaultValue);
+ assertThat(currentEntry).isEqualTo(defaultEntry);
+ assertThat(currentSummary).isEqualTo(defaultEntry);
}
/**
- * Test that log level is changed to WARN when WARN is selected
+ * Test that our preference key returned by our controller matches the one defined in the XML
+ * definition.
*/
@Test
- public void onPreferenceChanged_enableBluetoothStackWarnLogLevel() {
- mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_WARN_INDEX]
- .toString());
-
- final String persistedLogLevel = SystemProperties.get(
- BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
- final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
- assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_WARN_INDEX]
- .toString());
- assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_WARN_INDEX].toString());
-
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
-
- [BTSTACK_LOG_MODE_WARN_INDEX].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
- [BTSTACK_LOG_MODE_WARN_INDEX].toString());
- }
-
- /**
- * Test that log level is changed to ERROR when ERROR is selected
- */
- @Test
- public void onPreferenceChanged_enableBluetoothStackErrorLogLevel() {
- mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_ERROR_INDEX]
- .toString());
-
- final String persistedLogLevel = SystemProperties.get(
- BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
- final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
- assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_ERROR_INDEX]
- .toString());
- assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_ERROR_INDEX].toString());
-
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
- [BTSTACK_LOG_MODE_ERROR_INDEX].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
- [BTSTACK_LOG_MODE_ERROR_INDEX].toString());
- }
-
- /**
- * Test that preference is disabled when developer options is disabled
- * Log level is also reset to default
- */
- @Test
- public void onDeveloperOptionsDisabled_shouldDisablePreference() {
- mController.onDeveloperOptionsDisabled();
- assertThat(mPreference.isEnabled()).isFalse();
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues[mController
- .getDefaultModeIndex()].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries[mController
- .getDefaultModeIndex()].toString());
+ public void getPreferenceKey_matchesXmlDefinedPreferenceKey() {
+ assertThat(mController.getPreferenceKey()).isEqualTo(XML_DEFINED_PREFERENCE_KEY);
}
}