Merge "Enable presubmit biometrics unit tests" into udc-dev
diff --git a/protos/fuelgauge_log.proto b/protos/fuelgauge_log.proto
index cf87dc7..150c2e2 100644
--- a/protos/fuelgauge_log.proto
+++ b/protos/fuelgauge_log.proto
@@ -19,10 +19,12 @@
APPLY = 2;
RESET = 3;
RESTORE = 4;
+ BACKUP = 5;
+ FORCE_RESET = 6;
}
optional string package_name = 1;
optional Action action = 2;
optional string action_description = 3;
optional int64 timestamp = 4;
-}
\ No newline at end of file
+}
diff --git a/res/drawable/ic_check_circle_filled_24dp.xml b/res/drawable/ic_check_circle_filled_24dp.xml
index 9d2e296..507bf67 100644
--- a/res/drawable/ic_check_circle_filled_24dp.xml
+++ b/res/drawable/ic_check_circle_filled_24dp.xml
@@ -20,7 +20,7 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
- android:tint="?androidprv:attr/materialColorPrimaryContainer">
+ android:tint="?android:attr/colorPrimary">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10c5.52,0 10,-4.48 10,-10S17.52,2 12,2zM10.59,16.6l-4.24,-4.24l1.41,-1.41l2.83,2.83l5.66,-5.66l1.41,1.41L10.59,16.6z"/>
diff --git a/res/layout-land/udfps_enroll_enrolling.xml b/res/layout-land/udfps_enroll_enrolling.xml
index f323788..743684f 100644
--- a/res/layout-land/udfps_enroll_enrolling.xml
+++ b/res/layout-land/udfps_enroll_enrolling.xml
@@ -96,4 +96,6 @@
</LinearLayout>
</LinearLayout>
+
+ <include layout="@layout/udfps_enroll_view" />
</com.google.android.setupdesign.GlifLayout>
\ No newline at end of file
diff --git a/res/layout/udfps_enroll_enrolling.xml b/res/layout/udfps_enroll_enrolling.xml
index c97591d..05556ff 100644
--- a/res/layout/udfps_enroll_enrolling.xml
+++ b/res/layout/udfps_enroll_enrolling.xml
@@ -18,6 +18,7 @@
<com.google.android.setupdesign.GlifLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/setup_wizard_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -41,10 +42,11 @@
<FrameLayout
android:id="@+id/layout_container"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="0dp"
android:clipChildren="false"
android:clipToPadding="false"
- android:layout_gravity="center_horizontal|bottom">
+ android:layout_gravity="center_horizontal|bottom"
+ tools:ignore="Suspicious0dp">
<!-- Animation res MUST be set in code -->
<com.airbnb.lottie.LottieAnimationView
@@ -59,6 +61,9 @@
android:clipChildren="false"
android:clipToPadding="false"
app:lottie_speed=".85" />
+
+ <include layout="@layout/udfps_enroll_view" />
+
</FrameLayout>
<TextView
diff --git a/res/values/config.xml b/res/values/config.xml
index 52d7183..334d4e5 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -526,6 +526,10 @@
<item>content://com.android.settings.slices/intent/media_output_indicator</item>
</string-array>
+ <!-- List containing the apps cannot be changed the battery optimize modes -->
+ <string-array name="config_disable_optimization_mode_apps" translatable="false">
+ </string-array>
+
<!-- Uri to query non-public Slice Uris. -->
<string name="config_non_public_slice_query_uri" translatable="false"></string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 877603c..405960b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -119,9 +119,9 @@
<!-- Connected devices settings. Title of the dialog to hint user to pair other ear of the hearing aid device. Shows when only one of the hearing aid device set is connected. [CHAR LIMIT=25] -->
<string name="bluetooth_pair_other_ear_dialog_title">Pair your other ear</string>
<!-- Connected devices settings. Message of the dialog to hint user to pair right ear of the hearing aid device. Shows when only left side of hearing aid device set is connected. [CHAR LIMIT=NONE] -->
- <string name="bluetooth_pair_other_ear_dialog_left_ear_message">Your left hearing aid is connected.\n\nTo pair the right one, make sure it\u2019s turned on and ready to pair.</string>
+ <string name="bluetooth_pair_other_ear_dialog_left_ear_message">Your left hearing device is connected.\n\nTo pair the right one, make sure it\u2019s turned on and ready to pair.</string>
<!-- Connected devices settings. Message of the dialog to hint user to pair other ear of the hearing aid device. Shows when only right side of the hearing aid device set is connected. [CHAR LIMIT=NONE] -->
- <string name="bluetooth_pair_other_ear_dialog_right_ear_message">Your right hearing aid is connected.\n\nTo pair the left one, make sure it\u2019s turned on and ready to pair.</string>
+ <string name="bluetooth_pair_other_ear_dialog_right_ear_message">Your right hearing device is connected.\n\nTo pair the left one, make sure it\u2019s turned on and ready to pair.</string>
<!-- Connected devices settings. Positive button of the dialog to help user to pair right ear of the hearing aid device. Dialog shows when only one of the hearing aid device set is connected. [CHAR LIMIT=20] -->
<string name="bluetooth_pair_other_ear_dialog_right_ear_positive_button">Pair right ear</string>
<!-- Connected devices settings. Positive button of the dialog to help user to pair left ear of the hearing aid device. Dialog shows when only one of the hearing aid device set is connected. [CHAR LIMIT=20] -->
@@ -129,7 +129,9 @@
<!-- Title for all hearing devices related controls section. [CHAR LIMIT=60] -->
<string name="bluetooth_device_controls_general">For all available hearing devices</string>
<!-- Connected devices settings. Title of the preference to show the entrance of the hearing device controls related page. [CHAR LIMIT=65] -->
- <string name="bluetooth_device_controls_title">Shortcuts & hearing aid compatibility</string>
+ <string name="bluetooth_device_controls_title">Hearing device settings</string>
+ <!-- Connected devices settings. Title of the preference to show the entrance of the hearing device controls related page. [CHAR LIMIT=65] -->
+ <string name="bluetooth_device_controls_summary">Audio output, shortcut, hearing aid compatibility</string>
<!-- Title for this device specific controls section. [CHAR LIMIT=30] -->
<string name="bluetooth_device_controls_specific">For this device</string>
<!-- Connected devices settings. Title of the preference to show the entrance of the audio output page. It can change different types of audio are played on phone or other bluetooth devices. [CHAR LIMIT=35] -->
@@ -1182,20 +1184,20 @@
<string name="current_screen_lock">Current screen lock</string>
<!-- Title for preference that guides the user through creating a backup unlock pattern for fingerprint [CHAR LIMIT=45]-->
- <string name="fingerprint_unlock_set_unlock_pattern">Fingerprint + Pattern</string>
+ <string name="fingerprint_unlock_set_unlock_pattern">Pattern \u2022 Fingerprint</string>
<!-- Title for preference that guides the user through creating a backup unlock PIN for fingerprint [CHAR LIMIT=45]-->
- <string name="fingerprint_unlock_set_unlock_pin">Fingerprint + PIN</string>
+ <string name="fingerprint_unlock_set_unlock_pin">PIN \u2022 Fingerprint</string>
<!-- Title for preference that guides the user through creating a backup unlock password for fingerprint [CHAR LIMIT=45]-->
- <string name="fingerprint_unlock_set_unlock_password">Fingerprint + Password</string>
+ <string name="fingerprint_unlock_set_unlock_password">Password \u2022 Fingerprint</string>
<!-- Title for preference that guides the user to skip fingerprint setup [CHAR LIMIT=60]-->
<string name="fingerprint_unlock_skip_fingerprint">Continue without fingerprint</string>
<!-- Title for preference that guides the user through creating a backup unlock pattern for Face Unlock [CHAR LIMIT=45]-->
- <string name="face_unlock_set_unlock_pattern">Face Unlock + Pattern</string>
+ <string name="face_unlock_set_unlock_pattern">Pattern \u2022 Face</string>
<!-- Title for preference that guides the user through creating a backup unlock PIN for Face Unlock [CHAR LIMIT=45]-->
- <string name="face_unlock_set_unlock_pin">Face Unlock + PIN</string>
+ <string name="face_unlock_set_unlock_pin">PIN \u2022 Face</string>
<!-- Title for preference that guides the user through creating a backup unlock password for Face Unlock [CHAR LIMIT=45]-->
- <string name="face_unlock_set_unlock_password">Face Unlock + Password</string>
+ <string name="face_unlock_set_unlock_password">Password \u2022 Face</string>
<!-- Title for preference that guides the user to skip Face Unlock setup [CHAR LIMIT=60]-->
<string name="face_unlock_skip_face">Continue without Face Unlock</string>
@@ -1505,6 +1507,8 @@
<string name="bluetooth_companion_app_remove_association_dialog_title">Disconnect App?</string>
<!-- Bluetooth device details companion apps. The body of confirmation dialog for remove association. [CHAR LIMIT=60] -->
<string name="bluetooth_companion_app_body"><xliff:g id="app_name" example="App Name">%1$s</xliff:g> app will no longer connect to your <xliff:g id="device_name" example="Device Name">%2$s</xliff:g></string>
+ <!-- Summary of Bluetooth LE Audio toggle in Device Details. [CHAR LIMIT=40] -->
+ <string name="device_details_leaudio_toggle_summary">Experimental. Improves audio quality.</string>
<!-- Bluetooth device details. In the confirmation dialog for unpairing a paired device, this is the label on the button that will complete the unpairing action. -->
<string name="bluetooth_unpair_dialog_forget_confirm_button">Forget device</string>
@@ -4670,7 +4674,7 @@
<!-- Introduction for the Hearing devices page to introduce feature. [CHAR LIMIT=NONE] -->
<string name="accessibility_hearingaid_intro">You can use hearing aids, cochlear implants, and other amplification devices with your phone</string>
<!-- Summary for the accessibility preference for hearing aid when not connected. [CHAR LIMIT=50] -->
- <string name="accessibility_hearingaid_not_connected_summary">No hearing aids connected</string>
+ <string name="accessibility_hearingaid_not_connected_summary">No hearing devices connected</string>
<!-- Summary for the accessibility preference for hearing aid when adding new devices. [CHAR LIMIT=50] -->
<string name="accessibility_hearingaid_adding_summary">Add hearing aids</string>
<!-- Title of the pair instruction dialog. Dialog shows to ask the user to make sure that their hearing aid devices are in pairing mode. [CHAR LIMIT=25] -->
@@ -5875,12 +5879,8 @@
<string name="add_account_label">Add account</string>
<!-- Label for the state of the work profile [CHAR LIMIT=80] -->
<string name="managed_profile_not_available_label">Work profile isn\u2019t available yet</string>
- <!-- This string is the title of a setting. If a user taps the setting, they can turn their work profile on or off. The work profile is a section of their phone that's managed by their employer. "Work" is an adjective. -->
- <string name="work_mode_label">Work profile</string>
- <!-- This string is located under a setting and describes what the setting does. It's letting a user know whether their work profile is on or off, and they can use the setting to turn it on or off. The work profile is a section of their phone that's managed by their employer. "Work" is an adjective.-->
- <string name="work_mode_on_summary">Managed by your organization</string>
- <!-- This string is located under a setting and describes what the setting does. It's letting a user know whether their work profile is on or off, and they can use the setting to turn it on or off. The work profile is a section of their phone that's managed by their employer. "Work" is an adjective.-->
- <string name="work_mode_off_summary">Apps and notifications are off</string>
+ <!-- This string is the title of a setting. If a user taps the setting, they can turn their work apps on or off. The work apps are a group of apps that are managed by the the user's employer. While this setting is off, the user cannot interact with those apps or get notifications from them. "Work" is an adjective. -->
+ <string name="work_mode_label">Work apps</string>
<!-- Button label to remove the work profile [CHAR LIMIT=35] -->
<string name="remove_managed_profile_label">Remove work profile</string>
<!-- Data synchronization settings screen, title of setting that controls whether background data should be used [CHAR LIMIT=30] -->
@@ -7173,7 +7173,7 @@
<string name="docking_sounds_title">Docking sounds</string>
<!-- Sound: Other sounds: Title for the option enabling touch sounds. [CHAR LIMIT=30] -->
- <string name="touch_sounds_title">Touch sounds</string>
+ <string name="touch_sounds_title">Tap & click sounds</string>
<!-- Sound: Other sounds: Title for the option enabling the vibrate icon. [CHAR LIMIT=50] -->
<string name="vibrate_icon_title">Always show icon when in vibrate mode</string>
@@ -9781,6 +9781,8 @@
<string name="cross_profile_calendar_title">Cross-profile calendar</string>
<!-- [CHAR LIMIT=NONE] Setting description. If the user turns on this setting, they can see their work events on their personal calendar. -->
<string name="cross_profile_calendar_summary">Show work events on your personal calendar</string>
+ <!-- [CHAR_LIMIT_NONE] Footer description. Explains to the user what will happen when work apps are turned off. -->
+ <string name="managed_profile_settings_footer">When work apps are off, they’re paused and can’t be accessed or send you notifications</string>
<!-- Used as title on the automatic storage manager settings. [CHAR LIMIT=60] -->
<string name="automatic_storage_manager_settings">Manage storage</string>
@@ -10311,7 +10313,7 @@
<b>Turn off this service?</b>
<br/>
<br/>
- Save info like passwords, passkeys, payment methods, and other info won\'t be filled
+ Saved info like passwords, passkeys, payment methods, and other info won\'t be filled
in when you sign in. To use your saved info, choose a password, passkey, or data
service.
]]>
diff --git a/res/xml/bluetooth_audio_routing_fragment.xml b/res/xml/accessibility_audio_routing_fragment.xml
similarity index 85%
rename from res/xml/bluetooth_audio_routing_fragment.xml
rename to res/xml/accessibility_audio_routing_fragment.xml
index 5edf6cd..12e75f2 100644
--- a/res/xml/bluetooth_audio_routing_fragment.xml
+++ b/res/xml/accessibility_audio_routing_fragment.xml
@@ -31,7 +31,7 @@
android:key="audio_routing_ringtone"
android:persistent="false"
android:title="@string/bluetooth_ringtone_title"
- settings:controller="com.android.settings.bluetooth.HearingDeviceRingtoneRoutingPreferenceController" />
+ settings:controller="com.android.settings.accessibility.HearingDeviceRingtoneRoutingPreferenceController" />
<ListPreference
android:entries="@array/bluetooth_audio_routing_titles"
@@ -40,7 +40,7 @@
android:key="audio_routing_call"
android:persistent="false"
android:title="@string/bluetooth_call_title"
- settings:controller="com.android.settings.bluetooth.HearingDeviceCallRoutingPreferenceController" />
+ settings:controller="com.android.settings.accessibility.HearingDeviceCallRoutingPreferenceController" />
<ListPreference
android:entries="@array/bluetooth_audio_routing_titles"
@@ -49,7 +49,7 @@
android:key="audio_routing_media"
android:persistent="false"
android:title="@string/bluetooth_media_title"
- settings:controller="com.android.settings.bluetooth.HearingDeviceMediaRoutingPreferenceController" />
+ settings:controller="com.android.settings.accessibility.HearingDeviceMediaRoutingPreferenceController" />
<ListPreference
android:entries="@array/bluetooth_audio_routing_titles"
@@ -58,7 +58,7 @@
android:key="audio_routing_system_sounds"
android:persistent="false"
android:title="@string/bluetooth_system_sounds_title"
- settings:controller="com.android.settings.bluetooth.HearingDeviceSystemSoundsRoutingPreferenceController" />
+ settings:controller="com.android.settings.accessibility.HearingDeviceSystemSoundsRoutingPreferenceController" />
<com.android.settings.accessibility.AccessibilityFooterPreference
android:key="hearing_device_footer"
diff --git a/res/xml/accessibility_hearing_aids.xml b/res/xml/accessibility_hearing_aids.xml
index e813cf2..b13eb74 100644
--- a/res/xml/accessibility_hearing_aids.xml
+++ b/res/xml/accessibility_hearing_aids.xml
@@ -45,8 +45,17 @@
<PreferenceCategory
android:key="hearing_options_category"
android:title="@string/accessibility_screen_option">
+
+ <Preference
+ android:key="audio_routing"
+ android:title="@string/bluetooth_audio_routing_title"
+ android:summary="@string/bluetooth_audio_routing_summary"
+ android:fragment="com.android.settings.accessibility.AccessibilityAudioRoutingFragment"
+ settings:controller="com.android.settings.accessibility.HearingAidAudioRoutingPreferenceController"/>
+
<SwitchPreference
android:key="hearing_aid_compatibility"
+ android:order="30"
android:title="@string/accessibility_hac_mode_title"
android:summary="@string/accessibility_hac_mode_summary"
settings:searchable="true"
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index 8d74a39..35359f7 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -69,12 +69,7 @@
android:key="device_companion_apps"/>
<PreferenceCategory
- android:key="device_controls_general"
- android:title="@string/bluetooth_device_controls_general"/>
-
- <PreferenceCategory
- android:key="device_controls_specific"
- android:title="@string/bluetooth_device_controls_specific"/>
+ android:key="device_controls_general" />
<PreferenceCategory
android:key="spatial_audio_group"/>
diff --git a/res/xml/managed_profile_settings.xml b/res/xml/managed_profile_settings.xml
index 20f6d3d..ddfb869 100644
--- a/res/xml/managed_profile_settings.xml
+++ b/res/xml/managed_profile_settings.xml
@@ -19,10 +19,9 @@
android:key="managed_profile_settings_screen"
android:title="@string/managed_profile_settings_title">
- <SwitchPreference
+ <com.android.settingslib.widget.MainSwitchPreference
android:key="work_mode"
android:title="@string/work_mode_label"
- android:summary="@string/summary_placeholder"
settings:controller="com.android.settings.accounts.WorkModePreferenceController"/>
<com.android.settingslib.RestrictedSwitchPreference
@@ -38,4 +37,9 @@
android:title="@string/cross_profile_calendar_title"
settings:controller="com.android.settings.accounts.CrossProfileCalendarPreferenceController"/>
+ <com.android.settingslib.widget.FooterPreference
+ android:title="@string/managed_profile_settings_footer"
+ android:key="managed_profile_footer"
+ settings:searchable="false"/>
+
</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/reset_dashboard_fragment.xml b/res/xml/reset_dashboard_fragment.xml
index 98f6c02..3bd7a13 100644
--- a/res/xml/reset_dashboard_fragment.xml
+++ b/res/xml/reset_dashboard_fragment.xml
@@ -38,9 +38,10 @@
settings:controller="com.android.settings.network.BluetoothWiFiResetPreferenceController" />
<!-- Reset app preferences -->
- <Preference
+ <com.android.settingslib.RestrictedPreference
android:key="reset_app_prefs"
- android:title="@string/reset_app_preferences" />
+ android:title="@string/reset_app_preferences"
+ settings:userRestriction="no_control_apps" />
<!-- Erase Euicc data -->
<Preference
diff --git a/src/com/android/settings/SettingsApplication.java b/src/com/android/settings/SettingsApplication.java
index 7d8055d..8c050ea 100644
--- a/src/com/android/settings/SettingsApplication.java
+++ b/src/com/android/settings/SettingsApplication.java
@@ -51,8 +51,9 @@
// Set Spa environment.
setSpaEnvironment();
- if (FeatureFlagUtils.isEnabled(this, FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)
- && ActivityEmbeddingUtils.isSettingsSplitEnabled(this)) {
+ if (ActivityEmbeddingUtils.isSettingsSplitEnabled(this)
+ && FeatureFlagUtils.isEnabled(this,
+ FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)) {
if (WizardManagerHelper.isUserSetupComplete(this)) {
new ActivityEmbeddingRulesController(this).initRules();
} else {
diff --git a/src/com/android/settings/accessibility/AccessibilityAudioRoutingFragment.java b/src/com/android/settings/accessibility/AccessibilityAudioRoutingFragment.java
new file mode 100644
index 0000000..6eb2112
--- /dev/null
+++ b/src/com/android/settings/accessibility/AccessibilityAudioRoutingFragment.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.accessibility;
+
+import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
+
+import android.app.settings.SettingsEnums;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+
+/** Settings fragment containing bluetooth audio routing. */
+public class AccessibilityAudioRoutingFragment extends RestrictedDashboardFragment {
+ private static final String TAG = "AccessibilityAudioRoutingFragment";
+
+ public AccessibilityAudioRoutingFragment() {
+ super(DISALLOW_CONFIG_BLUETOOTH);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.HEARING_AID_AUDIO_ROUTING;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.accessibility_audio_routing_fragment;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider(R.xml.accessibility_audio_routing_fragment);
+}
diff --git a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
index cd76b47..e4611fe 100644
--- a/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
+++ b/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceController.java
@@ -17,7 +17,6 @@
package com.android.settings.accessibility;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHapClient;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothLeAudio;
@@ -41,20 +40,14 @@
import com.android.settings.core.SubSettingLauncher;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.HapClientProfile;
import com.android.settingslib.bluetooth.HearingAidInfo;
-import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
-import java.util.ArrayList;
-import java.util.List;
import java.util.Set;
-import java.util.stream.Collectors;
/**
* Controller that shows and updates the bluetooth device name
@@ -73,10 +66,8 @@
};
private final LocalBluetoothManager mLocalBluetoothManager;
- private final BluetoothAdapter mBluetoothAdapter;
private final LocalBluetoothProfileManager mProfileManager;
- private final CachedBluetoothDeviceManager mCachedDeviceManager;
-
+ private final HearingAidHelper mHelper;
private FragmentManager mFragmentManager;
public AccessibilityHearingAidPreferenceController(Context context, String preferenceKey) {
@@ -84,8 +75,7 @@
mLocalBluetoothManager = com.android.settings.bluetooth.Utils.getLocalBluetoothManager(
context);
mProfileManager = mLocalBluetoothManager.getProfileManager();
- mCachedDeviceManager = mLocalBluetoothManager.getCachedDeviceManager();
- mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ mHelper = new HearingAidHelper(context);
}
@Override
@@ -96,7 +86,7 @@
@Override
public int getAvailabilityStatus() {
- return isHearingAidSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ return mHelper.isHearingAidSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
@Override
@@ -111,7 +101,7 @@
// Can't get connected hearing aids when hearing aids related profiles are not ready. The
// profiles will be ready after the services are connected. Needs to add listener and
// updates the information when all hearing aids related services are connected.
- if (isAnyHearingAidRelatedProfilesNotReady()) {
+ if (!mHelper.isAllHearingAidRelatedProfilesReady()) {
mProfileManager.addServiceListener(this);
}
}
@@ -126,7 +116,7 @@
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (TextUtils.equals(preference.getKey(), getPreferenceKey())) {
- final CachedBluetoothDevice device = getConnectedHearingAidDevice();
+ final CachedBluetoothDevice device = mHelper.getConnectedHearingAidDevice();
if (FeatureFlagUtils.isEnabled(mContext,
FeatureFlagUtils.SETTINGS_ACCESSIBILITY_HEARING_AID_PAGE)) {
launchHearingAidPage();
@@ -144,10 +134,7 @@
@Override
public CharSequence getSummary() {
- if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
- return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary);
- }
- final CachedBluetoothDevice device = getConnectedHearingAidDevice();
+ final CachedBluetoothDevice device = mHelper.getConnectedHearingAidDevice();
if (device == null) {
return mContext.getText(R.string.accessibility_hearingaid_not_connected_summary);
}
@@ -203,7 +190,7 @@
@Override
public void onServiceConnected() {
- if (!isAnyHearingAidRelatedProfilesNotReady()) {
+ if (mHelper.isAllHearingAidRelatedProfilesReady()) {
updateState(mHearingAidPreference);
mProfileManager.removeServiceListener(this);
}
@@ -218,53 +205,8 @@
mFragmentManager = fragmentManager;
}
- @VisibleForTesting
- CachedBluetoothDevice getConnectedHearingAidDevice() {
- final List<BluetoothDevice> deviceList = getConnectedHearingAidDeviceList();
- return deviceList.isEmpty() ? null : mCachedDeviceManager.findDevice(deviceList.get(0));
- }
-
private int getConnectedHearingAidDeviceNum() {
- return getConnectedHearingAidDeviceList().size();
- }
-
- private List<BluetoothDevice> getConnectedHearingAidDeviceList() {
- if (!isHearingAidSupported()) {
- return new ArrayList<>();
- }
- final List<BluetoothDevice> deviceList = new ArrayList<>();
- final HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
- if (hapClientProfile != null) {
- deviceList.addAll(hapClientProfile.getConnectedDevices());
- }
- final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
- if (hearingAidProfile != null) {
- deviceList.addAll(hearingAidProfile.getConnectedDevices());
- }
- return deviceList.stream()
- .distinct()
- .filter(d -> !mCachedDeviceManager.isSubDevice(d)).collect(Collectors.toList());
- }
-
- private boolean isHearingAidSupported() {
- if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
- return false;
- }
- final List<Integer> supportedList = mBluetoothAdapter.getSupportedProfiles();
- return supportedList.contains(BluetoothProfile.HEARING_AID)
- || supportedList.contains(BluetoothProfile.HAP_CLIENT);
- }
-
- private boolean isAnyHearingAidRelatedProfilesNotReady() {
- HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
- if (hearingAidProfile != null && !hearingAidProfile.isProfileReady()) {
- return true;
- }
- HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
- if (hapClientProfile != null && !hapClientProfile.isProfileReady()) {
- return true;
- }
- return false;
+ return mHelper.getConnectedHearingAidDeviceList().size();
}
@VisibleForTesting(otherwise = VisibleForTesting.NONE)
diff --git a/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java b/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java
index 547c456..33fef62 100644
--- a/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java
+++ b/src/com/android/settings/accessibility/AccessibilityHearingAidsFragment.java
@@ -39,7 +39,7 @@
private static final String TAG = "AccessibilityHearingAidsFragment";
private static final String KEY_HEARING_OPTIONS_CATEGORY = "hearing_options_category";
- private static final int FIRST_PREFERENCE_IN_CATEGORY_INDEX = -1;
+ private static final int SHORTCUT_PREFERENCE_IN_CATEGORY_INDEX = 20;
private String mFeatureName;
public AccessibilityHearingAidsFragment() {
@@ -65,7 +65,7 @@
final View view = super.onCreateView(inflater, container, savedInstanceState);
final PreferenceCategory controlCategory = findPreference(KEY_HEARING_OPTIONS_CATEGORY);
// To move the shortcut preference under controlCategory need to remove the original added.
- mShortcutPreference.setOrder(FIRST_PREFERENCE_IN_CATEGORY_INDEX);
+ mShortcutPreference.setOrder(SHORTCUT_PREFERENCE_IN_CATEGORY_INDEX);
getPreferenceScreen().removePreference(mShortcutPreference);
controlCategory.addPreference(mShortcutPreference);
return view;
diff --git a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
index 01158bf..b414add 100644
--- a/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/AccessibilityShortcutPreferenceFragment.java
@@ -322,6 +322,18 @@
getComponentName());
};
+ private static CharSequence getSoftwareShortcutTypeSummary(Context context) {
+ int resId;
+ if (AccessibilityUtil.isFloatingMenuEnabled(context)) {
+ resId = R.string.accessibility_shortcut_edit_summary_software;
+ } else if (AccessibilityUtil.isGestureNavigateEnabled(context)) {
+ resId = R.string.accessibility_shortcut_edit_summary_software_gesture;
+ } else {
+ resId = R.string.accessibility_shortcut_edit_summary_software;
+ }
+ return context.getText(resId);
+ }
+
/**
* This method will be invoked when a button in the tutorial dialog is clicked.
*
@@ -429,11 +441,9 @@
getComponentName().flattenToString(), AccessibilityUtil.UserShortcutType.SOFTWARE);
final List<CharSequence> list = new ArrayList<>();
- final CharSequence softwareTitle = context.getText(
- R.string.accessibility_shortcut_edit_summary_software);
if (hasShortcutType(shortcutTypes, AccessibilityUtil.UserShortcutType.SOFTWARE)) {
- list.add(softwareTitle);
+ list.add(getSoftwareShortcutTypeSummary(context));
}
if (hasShortcutType(shortcutTypes, AccessibilityUtil.UserShortcutType.HARDWARE)) {
final CharSequence hardwareTitle = context.getText(
@@ -443,7 +453,7 @@
// Show software shortcut if first time to use.
if (list.isEmpty()) {
- list.add(softwareTitle);
+ list.add(getSoftwareShortcutTypeSummary(context));
}
return CaseMap.toTitle().wholeString().noLowercase().apply(Locale.getDefault(), /* iter= */
diff --git a/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceController.java
new file mode 100644
index 0000000..54022ef
--- /dev/null
+++ b/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceController.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.accessibility;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * The controller of the audio routing.
+ */
+public class HearingAidAudioRoutingPreferenceController extends BasePreferenceController {
+ public HearingAidAudioRoutingPreferenceController(Context context,
+ String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_AUDIO_ROUTING)
+ ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+}
diff --git a/src/com/android/settings/accessibility/HearingAidHelper.java b/src/com/android/settings/accessibility/HearingAidHelper.java
new file mode 100644
index 0000000..66a37f8
--- /dev/null
+++ b/src/com/android/settings/accessibility/HearingAidHelper.java
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.accessibility;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HapClientProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * A helper class to get and check hearing aids and its status.
+ */
+public class HearingAidHelper {
+
+ private final BluetoothAdapter mBluetoothAdapter;
+ private final LocalBluetoothProfileManager mProfileManager;
+ private final CachedBluetoothDeviceManager mCachedDeviceManager;
+
+ public HearingAidHelper(Context context) {
+ final LocalBluetoothManager localBluetoothManager =
+ com.android.settings.bluetooth.Utils.getLocalBluetoothManager(context);
+ mProfileManager = localBluetoothManager.getProfileManager();
+ mCachedDeviceManager = localBluetoothManager.getCachedDeviceManager();
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ }
+
+ /**
+ * Gets the connected hearing aids device whose profiles are
+ * {@link BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#HAP_CLIENT}.
+ *
+ * @return a list of hearing aids {@link BluetoothDevice} objects
+ */
+ public List<BluetoothDevice> getConnectedHearingAidDeviceList() {
+ if (!isHearingAidSupported()) {
+ return new ArrayList<>();
+ }
+ final List<BluetoothDevice> deviceList = new ArrayList<>();
+ final HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
+ if (hapClientProfile != null) {
+ deviceList.addAll(hapClientProfile.getConnectedDevices());
+ }
+ final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+ if (hearingAidProfile != null) {
+ deviceList.addAll(hearingAidProfile.getConnectedDevices());
+ }
+ return deviceList.stream()
+ .distinct()
+ .filter(d -> !mCachedDeviceManager.isSubDevice(d)).collect(Collectors.toList());
+ }
+
+ /**
+ * Gets the first connected hearing aids device.
+ *
+ * @return a {@link CachedBluetoothDevice} that is hearing aids device
+ */
+ public CachedBluetoothDevice getConnectedHearingAidDevice() {
+ final List<BluetoothDevice> deviceList = getConnectedHearingAidDeviceList();
+ return deviceList.isEmpty() ? null : mCachedDeviceManager.findDevice(deviceList.get(0));
+ }
+
+ /**
+ * Checks if {@link BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#HAP_CLIENT}
+ * supported.
+ */
+ public boolean isHearingAidSupported() {
+ if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
+ return false;
+ }
+ final List<Integer> supportedList = mBluetoothAdapter.getSupportedProfiles();
+ return supportedList.contains(BluetoothProfile.HEARING_AID)
+ || supportedList.contains(BluetoothProfile.HAP_CLIENT);
+ }
+
+ /**
+ * Checks if {@link BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#HAP_CLIENT}
+ * profiles all ready.
+ */
+ public boolean isAllHearingAidRelatedProfilesReady() {
+ HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+ if (hearingAidProfile != null && !hearingAidProfile.isProfileReady()) {
+ return false;
+ }
+ HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
+ if (hapClientProfile != null && !hapClientProfile.isProfileReady()) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceController.java
similarity index 79%
rename from src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceController.java
index e93863a..3599f48 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import android.content.ContentResolver;
import android.content.Context;
@@ -47,19 +47,24 @@
private static final String TAG = "HARoutingBasePreferenceController";
private static final boolean DEBUG = false;
- private final HearingAidAudioRoutingHelper mHelper;
+ private final HearingAidAudioRoutingHelper mAudioRoutingHelper;
+ private final HearingAidHelper mHearingAidHelper;
public HearingDeviceAudioRoutingBasePreferenceController(Context context,
String preferenceKey) {
- super(context, preferenceKey);
- mHelper = new HearingAidAudioRoutingHelper(context);
+ this(context, preferenceKey,
+ new HearingAidAudioRoutingHelper(context),
+ new HearingAidHelper(context));
}
@VisibleForTesting
public HearingDeviceAudioRoutingBasePreferenceController(Context context,
- String preferenceKey, HearingAidAudioRoutingHelper helper) {
+ String preferenceKey, HearingAidAudioRoutingHelper audioRoutingHelper,
+ HearingAidHelper hearingAidHelper) {
super(context, preferenceKey);
- mHelper = helper;
+
+ mAudioRoutingHelper = audioRoutingHelper;
+ mHearingAidHelper = hearingAidHelper;
}
@Override
@@ -81,7 +86,11 @@
final Integer routingValue = Ints.tryParse((String) newValue);
saveRoutingValue(mContext, routingValue);
- trySetAudioRoutingConfig(getSupportedAttributeList(), getHearingDevice(), routingValue);
+ final CachedBluetoothDevice device = mHearingAidHelper.getConnectedHearingAidDevice();
+ if (device != null) {
+ trySetAudioRoutingConfig(getSupportedAttributeList(),
+ mHearingAidHelper.getConnectedHearingAidDevice(), routingValue);
+ }
return true;
}
@@ -89,10 +98,10 @@
private void trySetAudioRoutingConfig(int[] audioAttributes,
CachedBluetoothDevice hearingDevice,
@HearingAidAudioRoutingConstants.RoutingValue int routingValue) {
- final List<AudioProductStrategy> supportedStrategies = mHelper.getSupportedStrategies(
- audioAttributes);
+ final List<AudioProductStrategy> supportedStrategies =
+ mAudioRoutingHelper.getSupportedStrategies(audioAttributes);
final AudioDeviceAttributes hearingDeviceAttributes =
- mHelper.getMatchedHearingDeviceAttributes(hearingDevice);
+ mAudioRoutingHelper.getMatchedHearingDeviceAttributes(hearingDevice);
if (hearingDeviceAttributes == null) {
if (DEBUG) {
Log.d(TAG,
@@ -103,8 +112,8 @@
return;
}
- final boolean status = mHelper.setPreferredDeviceRoutingStrategies(supportedStrategies,
- hearingDeviceAttributes, routingValue);
+ final boolean status = mAudioRoutingHelper.setPreferredDeviceRoutingStrategies(
+ supportedStrategies, hearingDeviceAttributes, routingValue);
if (!status) {
final List<String> strategiesName = supportedStrategies.stream()
@@ -122,12 +131,6 @@
protected abstract int[] getSupportedAttributeList();
/**
- * Gets the {@link CachedBluetoothDevice} hearing device that is used to configure audio
- * routing.
- */
- protected abstract CachedBluetoothDevice getHearingDevice();
-
- /**
* Saves the routing value.
*
* @param context the valid context used to get the {@link ContentResolver}
diff --git a/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceController.java
similarity index 81%
rename from src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceController.java
index 4e5e193..8ca2663 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import android.content.Context;
import android.provider.Settings;
@@ -35,15 +35,6 @@
super(context, preferenceKey);
}
- /**
- * Initializes objects in this controller. Need to call this before using the controller.
- *
- * @param cachedBluetoothDevice the hearing device to configure audio routing
- */
- public void init(CachedBluetoothDevice cachedBluetoothDevice) {
- mHearingDevice = cachedBluetoothDevice;
- }
-
@Override
public int getAvailabilityStatus() {
return Utils.isVoiceCapable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
@@ -55,11 +46,6 @@
}
@Override
- protected CachedBluetoothDevice getHearingDevice() {
- return mHearingDevice;
- }
-
- @Override
protected void saveRoutingValue(Context context, int routingValue) {
Settings.Secure.putInt(context.getContentResolver(),
Settings.Secure.HEARING_AID_CALL_ROUTING, routingValue);
diff --git a/src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceMediaRoutingPreferenceController.java
similarity index 79%
rename from src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceMediaRoutingPreferenceController.java
index 1ea36c7..cd99ce0 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceMediaRoutingPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceMediaRoutingPreferenceController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import android.content.Context;
import android.provider.Settings;
@@ -34,15 +34,6 @@
super(context, preferenceKey);
}
- /**
- * Initializes objects in this controller. Need to call this before using the controller.
- *
- * @param cachedBluetoothDevice the hearing device to configure audio routing
- */
- public void init(CachedBluetoothDevice cachedBluetoothDevice) {
- mHearingDevice = cachedBluetoothDevice;
- }
-
@Override
protected int[] getSupportedAttributeList() {
return HearingAidAudioRoutingConstants.MEDIA_ROUTING_ATTRIBUTES;
@@ -50,11 +41,6 @@
}
@Override
- protected CachedBluetoothDevice getHearingDevice() {
- return mHearingDevice;
- }
-
- @Override
protected void saveRoutingValue(Context context, int routingValue) {
Settings.Secure.putInt(context.getContentResolver(),
Settings.Secure.HEARING_AID_MEDIA_ROUTING, routingValue);
diff --git a/src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceRingtoneRoutingPreferenceController.java
similarity index 79%
rename from src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceRingtoneRoutingPreferenceController.java
index 006cb6b..3e8f79c 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceRingtoneRoutingPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceRingtoneRoutingPreferenceController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import android.content.Context;
import android.provider.Settings;
@@ -34,15 +34,6 @@
super(context, preferenceKey);
}
- /**
- * Initializes objects in this controller. Need to call this before using the controller.
- *
- * @param cachedBluetoothDevice the hearing device to configure audio routing
- */
- public void init(CachedBluetoothDevice cachedBluetoothDevice) {
- mHearingDevice = cachedBluetoothDevice;
- }
-
@Override
protected int[] getSupportedAttributeList() {
return HearingAidAudioRoutingConstants.RINGTONE_ROUTING_ATTRIBUTE;
@@ -50,11 +41,6 @@
}
@Override
- protected CachedBluetoothDevice getHearingDevice() {
- return mHearingDevice;
- }
-
- @Override
protected void saveRoutingValue(Context context, int routingValue) {
Settings.Secure.putInt(context.getContentResolver(),
Settings.Secure.HEARING_AID_RINGTONE_ROUTING, routingValue);
diff --git a/src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java b/src/com/android/settings/accessibility/HearingDeviceSystemSoundsRoutingPreferenceController.java
similarity index 80%
rename from src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java
rename to src/com/android/settings/accessibility/HearingDeviceSystemSoundsRoutingPreferenceController.java
index a66cfab..1bc0090 100644
--- a/src/com/android/settings/bluetooth/HearingDeviceSystemSoundsRoutingPreferenceController.java
+++ b/src/com/android/settings/accessibility/HearingDeviceSystemSoundsRoutingPreferenceController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import android.content.Context;
import android.provider.Settings;
@@ -35,15 +35,6 @@
super(context, preferenceKey);
}
- /**
- * Initializes objects in this controller. Need to call this before using the controller.
- *
- * @param cachedBluetoothDevice the hearing device to configure audio routing
- */
- public void init(CachedBluetoothDevice cachedBluetoothDevice) {
- mHearingDevice = cachedBluetoothDevice;
- }
-
@Override
protected int[] getSupportedAttributeList() {
return HearingAidAudioRoutingConstants.SYSTEM_SOUNDS_ROUTING_ATTRIBUTES;
@@ -51,11 +42,6 @@
}
@Override
- protected CachedBluetoothDevice getHearingDevice() {
- return mHearingDevice;
- }
-
- @Override
protected void saveRoutingValue(Context context, int routingValue) {
Settings.Secure.putInt(context.getContentResolver(),
Settings.Secure.HEARING_AID_SYSTEM_SOUNDS_ROUTING, routingValue);
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
index 2011725..1270671 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -249,12 +249,18 @@
super.onProcessArguments(arguments);
}
- private void addAlwaysOnSetting(PreferenceCategory generalCategory) {
- if (!DeviceConfig.getBoolean(
+ private boolean isAlwaysOnSettingEnabled() {
+ final boolean defaultValue = getContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_magnification_always_on_enabled);
+
+ return DeviceConfig.getBoolean(
DeviceConfig.NAMESPACE_WINDOW_MANAGER,
"AlwaysOnMagnifier__enable_always_on_magnifier",
- false
- )) {
+ defaultValue
+ );
+ }
+ private void addAlwaysOnSetting(PreferenceCategory generalCategory) {
+ if (!isAlwaysOnSettingEnabled()) {
return;
}
diff --git a/src/com/android/settings/accounts/ContactSearchPreferenceController.java b/src/com/android/settings/accounts/ContactSearchPreferenceController.java
index 5e4ef48..87dabd8 100644
--- a/src/com/android/settings/accounts/ContactSearchPreferenceController.java
+++ b/src/com/android/settings/accounts/ContactSearchPreferenceController.java
@@ -20,37 +20,38 @@
import android.os.UserManager;
import android.provider.Settings;
-import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import com.android.settings.R;
import com.android.settings.Utils;
-import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.TogglePreferenceController;
import com.android.settings.slices.SliceData;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedSwitchPreference;
-public class ContactSearchPreferenceController extends BasePreferenceController implements
- Preference.OnPreferenceChangeListener {
+import org.jetbrains.annotations.NotNull;
- private UserHandle mManagedUser;
+public class ContactSearchPreferenceController extends TogglePreferenceController implements
+ Preference.OnPreferenceChangeListener, DefaultLifecycleObserver,
+ ManagedProfileQuietModeEnabler.QuietModeChangeListener {
+
+ private final ManagedProfileQuietModeEnabler mQuietModeEnabler;
+ private final UserHandle mManagedUser;
+ private Preference mPreference;
public ContactSearchPreferenceController(Context context, String key) {
super(context, key);
- // Set default managed profile for the current user, otherwise isAvailable will be false and
- // the setting won't be searchable.
- UserManager userManager = context.getSystemService(UserManager.class);
- mManagedUser = Utils.getManagedProfile(userManager);
- }
-
- @VisibleForTesting
- void setManagedUser(UserHandle managedUser) {
- mManagedUser = managedUser;
+ mManagedUser = Utils.getManagedProfile(context.getSystemService(UserManager.class));
+ mQuietModeEnabler = new ManagedProfileQuietModeEnabler(context, this);
}
@Override
public int getAvailabilityStatus() {
- return (mManagedUser != null) ? AVAILABLE : DISABLED_FOR_USER;
+ return mQuietModeEnabler.isAvailable() ? AVAILABLE : DISABLED_FOR_USER;
}
@Override
@@ -59,6 +60,7 @@
if (preference instanceof RestrictedSwitchPreference) {
final RestrictedSwitchPreference pref = (RestrictedSwitchPreference) preference;
pref.setChecked(isChecked());
+ pref.setEnabled(!mQuietModeEnabler.isQuietModeEnabled());
if (mManagedUser != null) {
final RestrictedLockUtils.EnforcedAdmin enforcedAdmin =
RestrictedLockUtilsInternal.checkIfRemoteContactSearchDisallowed(
@@ -68,26 +70,48 @@
}
}
- private boolean isChecked() {
- if (mManagedUser == null) {
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ updateState(mPreference);
+ }
+
+ @Override
+ public void onStart(@NotNull LifecycleOwner lifecycleOwner) {
+ lifecycleOwner.getLifecycle().addObserver(mQuietModeEnabler);
+ }
+
+ @Override
+ public void onStop(@NotNull LifecycleOwner lifecycleOwner) {
+ lifecycleOwner.getLifecycle().removeObserver(mQuietModeEnabler);
+ }
+
+ @Override
+ public boolean isChecked() {
+ if (mManagedUser == null || mQuietModeEnabler.isQuietModeEnabled()) {
return false;
}
return 0 != Settings.Secure.getIntForUser(mContext.getContentResolver(),
MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, mManagedUser.getIdentifier());
}
- private boolean setChecked(boolean isChecked) {
- if (mManagedUser != null) {
- final int value = isChecked ? 1 : 0;
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, value, mManagedUser.getIdentifier());
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ if (mManagedUser == null || mQuietModeEnabler.isQuietModeEnabled()) {
+ return false;
}
+ final int value = isChecked ? 1 : 0;
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, value, mManagedUser.getIdentifier());
return true;
}
@Override
- public final boolean onPreferenceChange(Preference preference, Object newValue) {
- return setChecked((boolean) newValue);
+ public void onQuietModeChanged() {
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
}
@Override
@@ -95,4 +119,9 @@
public int getSliceType() {
return SliceData.SliceType.SWITCH;
}
-}
\ No newline at end of file
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_accounts;
+ }
+}
diff --git a/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java b/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java
new file mode 100644
index 0000000..989be09
--- /dev/null
+++ b/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.accounts;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+
+import com.android.settings.Utils;
+
+import javax.annotation.Nullable;
+
+/**
+ * A class that controls the managed profile's quiet mode, listens to quiet mode changes and
+ * modifies managed profile settings. The user facing term for quiet mode is "work apps".
+ */
+final class ManagedProfileQuietModeEnabler implements DefaultLifecycleObserver {
+
+ private static final String TAG = "QuietModeEnabler";
+ private final Context mContext;
+ private final QuietModeChangeListener mListener;
+ @Nullable private final UserHandle mManagedProfile;
+ private final UserManager mUserManager;
+
+ public interface QuietModeChangeListener {
+ /** Called when quiet mode has changed. */
+ void onQuietModeChanged();
+ }
+
+ ManagedProfileQuietModeEnabler(Context context, QuietModeChangeListener listener) {
+ mContext = context;
+ mListener = listener;
+ mUserManager = context.getSystemService(UserManager.class);
+ mManagedProfile = Utils.getManagedProfile(mUserManager);
+ }
+
+ public void setQuietModeEnabled(boolean enabled) {
+ if (mManagedProfile != null) {
+ mUserManager.requestQuietModeEnabled(enabled, mManagedProfile);
+ }
+ }
+
+ public boolean isQuietModeEnabled() {
+ return mManagedProfile != null && mUserManager.isQuietModeEnabled(mManagedProfile);
+ }
+
+ @Override
+ public void onStart(@NonNull LifecycleOwner owner) {
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
+ intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
+ mContext.registerReceiver(mReceiver, intentFilter, Context.RECEIVER_NOT_EXPORTED);
+ }
+
+ @Override
+ public void onStop(@NonNull LifecycleOwner owner) {
+ mContext.unregisterReceiver(mReceiver);
+ }
+
+ public boolean isAvailable() {
+ return (mManagedProfile != null);
+ }
+
+ private void refreshQuietMode() {
+ if (mListener != null) {
+ mListener.onQuietModeChanged();
+ }
+ }
+
+ /**
+ * Receiver that listens to {@link Intent#ACTION_MANAGED_PROFILE_AVAILABLE} and
+ * {@link Intent#ACTION_MANAGED_PROFILE_UNAVAILABLE}, and updates the work mode
+ */
+ @VisibleForTesting
+ final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent == null) {
+ return;
+ }
+ String action = intent.getAction();
+ Log.v(TAG, "Received broadcast: " + action);
+
+ if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
+ || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
+ int intentUserIdentifier = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ UserHandle.USER_NULL);
+ if (intentUserIdentifier == mManagedProfile.getIdentifier()) {
+ refreshQuietMode();
+ } else {
+ Log.w(TAG, "Managed profile broadcast ID: " + intentUserIdentifier
+ + " does not match managed user: " + mManagedProfile);
+ }
+ } else {
+ Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
+ }
+ }
+ };
+}
diff --git a/src/com/android/settings/accounts/WorkModePreferenceController.java b/src/com/android/settings/accounts/WorkModePreferenceController.java
index 1941de4..a261afc 100644
--- a/src/com/android/settings/accounts/WorkModePreferenceController.java
+++ b/src/com/android/settings/accounts/WorkModePreferenceController.java
@@ -1,165 +1,90 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
+ * 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.
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
package com.android.settings.accounts;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING_OFF_SUMMARY;
-import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_SETTING_ON_SUMMARY;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.util.Log;
-import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.TwoStatePreference;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
-import com.android.settings.Utils;
-import com.android.settings.core.BasePreferenceController;
import com.android.settings.slices.SliceData;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStart;
-import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settings.widget.SettingsMainSwitchPreferenceController;
+import com.android.settingslib.widget.MainSwitchPreference;
-public class WorkModePreferenceController extends BasePreferenceController implements
- Preference.OnPreferenceChangeListener, LifecycleObserver, OnStart, OnStop {
+import org.jetbrains.annotations.NotNull;
- private static final String TAG = "WorkModeController";
- private UserManager mUserManager;
- private UserHandle mManagedUser;
- private DevicePolicyManager mDevicePolicyManager;
+public class WorkModePreferenceController extends SettingsMainSwitchPreferenceController
+ implements Preference.OnPreferenceChangeListener, DefaultLifecycleObserver,
+ ManagedProfileQuietModeEnabler.QuietModeChangeListener {
- private Preference mPreference;
- private IntentFilter mIntentFilter;
+ private final ManagedProfileQuietModeEnabler mQuietModeEnabler;
public WorkModePreferenceController(Context context, String key) {
super(context, key);
- mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
- mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
- mIntentFilter = new IntentFilter();
- mIntentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
- mIntentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
- // Set default managed profile for the current user, otherwise isAvailable will be false and
- // the setting won't be searchable.
- mManagedUser = Utils.getManagedProfile(mUserManager);
- }
-
- @VisibleForTesting
- void setManagedUser(UserHandle managedUser) {
- mManagedUser = managedUser;
- }
-
- @Override
- public void onStart() {
- mContext.registerReceiver(mReceiver, mIntentFilter,
- Context.RECEIVER_EXPORTED_UNAUDITED);
- }
-
- @Override
- public void onStop() {
- mContext.unregisterReceiver(mReceiver);
+ mQuietModeEnabler = new ManagedProfileQuietModeEnabler(context, this);
}
@Override
public int getAvailabilityStatus() {
- return (mManagedUser != null) ? AVAILABLE : DISABLED_FOR_USER;
+ return (mQuietModeEnabler.isAvailable()) ? AVAILABLE : DISABLED_FOR_USER;
}
@Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mPreference = screen.findPreference(getPreferenceKey());
+ public void onStart(@NotNull LifecycleOwner lifecycleOwner) {
+ lifecycleOwner.getLifecycle().addObserver(mQuietModeEnabler);
}
@Override
- public CharSequence getSummary() {
- if (isChecked()) {
- return mDevicePolicyManager.getResources().getString(
- WORK_PROFILE_SETTING_ON_SUMMARY,
- () -> mContext.getString(R.string.work_mode_on_summary));
- }
-
- return mDevicePolicyManager.getResources().getString(
- WORK_PROFILE_SETTING_OFF_SUMMARY,
- () -> mContext.getString(R.string.work_mode_off_summary));
+ public void onStop(@NotNull LifecycleOwner lifecycleOwner) {
+ lifecycleOwner.getLifecycle().removeObserver(mQuietModeEnabler);
}
- private boolean isChecked() {
- boolean isWorkModeOn = false;
- if (mUserManager != null && mManagedUser != null) {
- isWorkModeOn = !mUserManager.isQuietModeEnabled(mManagedUser);
- }
- return isWorkModeOn;
+ @Override
+ public boolean isChecked() {
+ return !mQuietModeEnabler.isQuietModeEnabled();
}
- private boolean setChecked(boolean isChecked) {
- if (mUserManager != null && mManagedUser != null) {
- final boolean quietModeEnabled = !isChecked;
- mUserManager.requestQuietModeEnabled(quietModeEnabled, mManagedUser);
- }
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ mQuietModeEnabler.setQuietModeEnabled(!isChecked);
return true;
}
@Override
- public void updateState(Preference preference) {
- super.updateState(preference);
- if (preference instanceof TwoStatePreference) {
- ((TwoStatePreference) preference).setChecked(isChecked());
- }
+ public void onQuietModeChanged() {
+ updateState(mSwitchPreference);
}
@Override
- public final boolean onPreferenceChange(Preference preference, Object newValue) {
- return setChecked((boolean) newValue);
- }
-
- /**
- * Receiver that listens to {@link Intent#ACTION_MANAGED_PROFILE_AVAILABLE} and
- * {@link Intent#ACTION_MANAGED_PROFILE_UNAVAILABLE}, and updates the work mode
- */
- @VisibleForTesting
- final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent == null) {
- return;
- }
- final String action = intent.getAction();
- Log.v(TAG, "Received broadcast: " + action);
-
- if (Intent.ACTION_MANAGED_PROFILE_AVAILABLE.equals(action)
- || Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE.equals(action)) {
- if (intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
- UserHandle.USER_NULL) == mManagedUser.getIdentifier()) {
- updateState(mPreference);
- }
- return;
- }
- Log.w(TAG, "Cannot handle received broadcast: " + intent.getAction());
- }
- };
-
- @Override
@SliceData.SliceType
public int getSliceType() {
return SliceData.SliceType.SWITCH;
}
-}
\ No newline at end of file
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_accounts;
+ }
+
+ @VisibleForTesting
+ void setPreference(MainSwitchPreference preference) {
+ mSwitchPreference = preference;
+ }
+}
diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
index ae890f8..67d56e0 100644
--- a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
+++ b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
@@ -97,16 +97,24 @@
* </ul>
*/
public static boolean isEmbeddingActivityEnabled(Context context) {
- boolean isFlagEnabled = FeatureFlagUtils.isEnabled(context,
- FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN);
- boolean isSettingsSplitSupported = isSettingsSplitEnabled(context);
- boolean isUserSetupComplete = WizardManagerHelper.isUserSetupComplete(context);
-
- Log.d(TAG, "isFlagEnabled = " + isFlagEnabled);
- Log.d(TAG, "isSettingsSplitSupported = " + isSettingsSplitSupported);
- Log.d(TAG, "isUserSetupComplete = " + isUserSetupComplete);
-
- return isFlagEnabled && isSettingsSplitSupported && isUserSetupComplete;
+ // Activity Embedding feature is not enabled if Settings doesn't enable large screen
+ // optimization or the device is not supported.
+ if (!isSettingsSplitEnabled(context)) {
+ Log.d(TAG, "isSettingsSplitSupported = false");
+ return false;
+ }
+ // Activity Embedding feature is not enabled if a user chooses to disable the feature.
+ if (!FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)) {
+ Log.d(TAG, "isFlagEnabled = false");
+ return false;
+ }
+ // Don't enable Activity embedding for setup wizard.
+ if (!WizardManagerHelper.isUserSetupComplete(context)) {
+ Log.d(TAG, "isUserSetupComplete = false");
+ return false;
+ }
+ Log.d(TAG, "isEmbeddingActivityEnabled = true");
+ return true;
}
/** Whether to show the regular or simplified homepage layout. */
@@ -120,8 +128,7 @@
* Check if activity is already embedded
*/
public static boolean isAlreadyEmbedded(Activity activity) {
- return ActivityEmbeddingController
- .getInstance(activity)
- .isActivityEmbedded(activity);
+ return isEmbeddingActivityEnabled(activity) && ActivityEmbeddingController.getInstance(
+ activity).isActivityEmbedded(activity);
}
}
diff --git a/src/com/android/settings/applications/ClonedAppsPreferenceController.java b/src/com/android/settings/applications/ClonedAppsPreferenceController.java
index a8a79f4..332df18 100644
--- a/src/com/android/settings/applications/ClonedAppsPreferenceController.java
+++ b/src/com/android/settings/applications/ClonedAppsPreferenceController.java
@@ -75,6 +75,9 @@
}
private void updatePreferenceSummary() {
+ if (!isAvailable()) {
+ return;
+ }
new AsyncTask<Void, Void, Integer[]>() {
@Override
diff --git a/src/com/android/settings/applications/credentials/CombinedProviderInfo.java b/src/com/android/settings/applications/credentials/CombinedProviderInfo.java
index 1fd3075..074fb7b 100644
--- a/src/com/android/settings/applications/credentials/CombinedProviderInfo.java
+++ b/src/com/android/settings/applications/credentials/CombinedProviderInfo.java
@@ -51,7 +51,7 @@
@Nullable List<CredentialProviderInfo> cpis,
@Nullable AutofillServiceInfo asi,
boolean isDefaultAutofillProvider,
- boolean IsPrimaryCredmanProvider) {
+ boolean isPrimaryCredmanProvider) {
if (cpis == null) {
mCredentialProviderInfos = new ArrayList<>();
} else {
@@ -59,11 +59,11 @@
}
mAutofillServiceInfo = asi;
mIsDefaultAutofillProvider = isDefaultAutofillProvider;
- mIsPrimaryCredmanProvider = IsPrimaryCredmanProvider;
+ mIsPrimaryCredmanProvider = isPrimaryCredmanProvider;
}
/** Returns the credential provider info. */
- @Nullable
+ @NonNull
public List<CredentialProviderInfo> getCredentialProviderInfos() {
return mCredentialProviderInfos;
}
@@ -85,11 +85,13 @@
/** Returns the app icon. */
@Nullable
public Drawable getAppIcon(@NonNull Context context, int userId) {
- IconDrawableFactory factory = IconDrawableFactory.newInstance(context);
+ final IconDrawableFactory factory = IconDrawableFactory.newInstance(context);
+ final ServiceInfo brandingService = getBrandingService();
+ final ApplicationInfo appInfo = getApplicationInfo();
+
Drawable icon = null;
- ServiceInfo brandingService = getBrandingService();
- if (brandingService != null) {
- icon = factory.getBadgedIcon(brandingService, getApplicationInfo(), userId);
+ if (brandingService != null && appInfo != null) {
+ icon = factory.getBadgedIcon(brandingService, appInfo, userId);
}
// If the branding service gave us a icon then use that.
@@ -98,7 +100,10 @@
}
// Otherwise fallback to the app icon and then the package name.
- return factory.getBadgedIcon(getApplicationInfo(), userId);
+ if (appInfo != null) {
+ return factory.getBadgedIcon(appInfo, userId);
+ }
+ return null;
}
/** Returns the app name. */
@@ -116,11 +121,14 @@
}
// Otherwise fallback to the app label and then the package name.
- name = getApplicationInfo().loadLabel(context.getPackageManager());
- if (TextUtils.isEmpty(name)) {
- name = getApplicationInfo().packageName;
+ final ApplicationInfo appInfo = getApplicationInfo();
+ if (appInfo != null) {
+ name = appInfo.loadLabel(context.getPackageManager());
+ if (TextUtils.isEmpty(name)) {
+ return appInfo.packageName;
+ }
}
- return name;
+ return "";
}
/** Gets the service to use for branding (name, icons). */
@@ -245,8 +253,10 @@
// Now go through and build the joint datasets.
List<CombinedProviderInfo> cmpi = new ArrayList<>();
for (String packageName : packageNames) {
- List<AutofillServiceInfo> asi = autofillServices.get(packageName);
- List<CredentialProviderInfo> cpi = credmanServices.get(packageName);
+ List<AutofillServiceInfo> asi =
+ autofillServices.getOrDefault(packageName, new ArrayList<>());
+ List<CredentialProviderInfo> cpi =
+ credmanServices.getOrDefault(packageName, new ArrayList<>());
// If there are multiple autofill services then pick the first one.
AutofillServiceInfo selectedAsi = null;
diff --git a/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java b/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java
index 742faf1..59c33b2 100644
--- a/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java
@@ -35,6 +35,7 @@
import com.android.settings.applications.defaultapps.DefaultAppPreferenceController;
import com.android.settingslib.applications.DefaultAppInfo;
+import java.util.ArrayList;
import java.util.List;
public class DefaultCombinedPreferenceController extends DefaultAppPreferenceController {
@@ -110,15 +111,19 @@
private List<CombinedProviderInfo> getAllProviders(int userId) {
final List<AutofillServiceInfo> autofillProviders =
AutofillServiceInfo.getAvailableServices(mContext, userId);
- final List<CredentialProviderInfo> credManProviders =
- mCredentialManager.getCredentialProviderServices(
- userId, CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY);
final String selectedAutofillProvider =
Settings.Secure.getStringForUser(
mContext.getContentResolver(),
DefaultCombinedPicker.AUTOFILL_SETTING,
userId);
+ final List<CredentialProviderInfo> credManProviders = new ArrayList<>();
+ if (mCredentialManager != null) {
+ credManProviders.addAll(
+ mCredentialManager.getCredentialProviderServices(
+ userId, CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY));
+ }
+
return CombinedProviderInfo.buildMergedList(
autofillProviders, credManProviders, selectedAutofillProvider);
}
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index a6e6ac4..e0f1b5f 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -16,8 +16,6 @@
package com.android.settings.applications.manageapplications;
-import static android.util.FeatureFlagUtils.SETTINGS_ENABLE_SPA;
-
import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING;
import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
@@ -67,7 +65,6 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
-import android.util.FeatureFlagUtils;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.view.LayoutInflater;
@@ -728,9 +725,6 @@
R.string.long_background_tasks_label);
break;
case LIST_TYPE_CLONED_APPS:
- if (!FeatureFlagUtils.isEnabled(getContext(), SETTINGS_ENABLE_SPA)) {
- return;
- }
int userId = UserHandle.getUserId(mCurrentUid);
UserInfo userInfo = mUserManager.getUserInfo(userId);
if (userInfo != null && !userInfo.isCloneProfile()) {
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
index bf83cb1..938c075 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrolling.java
@@ -261,6 +261,8 @@
int rotation = getApplicationContext().getDisplay().getRotation();
final GlifLayout layout = (GlifLayout) getLayoutInflater().inflate(
R.layout.udfps_enroll_enrolling, null, false);
+ final UdfpsEnrollView udfpsEnrollView = layout.findViewById(R.id.udfps_animation_view);
+ updateUdfpsEnrollView(udfpsEnrollView, props.get(0));
switch (rotation) {
case Surface.ROTATION_90:
final LinearLayout layoutContainer = layout.findViewById(
@@ -276,66 +278,52 @@
? 0 : (int) getResources().getDimension(
R.dimen.rotation_90_enroll_padding_end), 0);
layoutContainer.setLayoutParams(lp);
- if (FeatureFlagUtils.isEnabled(getApplicationContext(),
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
- final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(props.get(0));
- layout.addView(udfpsEnrollView);
- setOnHoverListener(true, layout, udfpsEnrollView);
- }
+
+ setOnHoverListener(true, layout, udfpsEnrollView);
setContentView(layout, lp);
break;
case Surface.ROTATION_0:
case Surface.ROTATION_180:
- if (FeatureFlagUtils.isEnabled(getApplicationContext(),
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
- final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(props.get(0));
- // In the portrait mode, set layout_container's height 0, so it's
- // always shown at the bottom of the screen.
- // Add udfps enroll view into layout_container instead of
- // udfps_enroll_enrolling, so that when the content is too long to
- // make udfps_enroll_enrolling larger than the screen, udfps enroll
- // view could still be set to right position by setting bottom margin to
- // its parent view (layout_container) because it's always at the
- // bottom of the screen.
- final FrameLayout portraitLayoutContainer = layout.findViewById(
- R.id.layout_container);
- final ViewGroup.LayoutParams containerLp =
- portraitLayoutContainer.getLayoutParams();
- containerLp.height = 0;
+ // In the portrait mode, layout_container's height is 0, so it's
+ // always shown at the bottom of the screen.
+ final FrameLayout portraitLayoutContainer = layout.findViewById(
+ R.id.layout_container);
- // In the portrait mode, the title and lottie animation view may
- // overlap when title needs three lines, so adding some paddings
- // between them, and adjusting the fp progress view here accordingly.
- final int layoutLottieAnimationPadding = (int) getResources()
- .getDimension(R.dimen.udfps_lottie_padding_top);
- portraitLayoutContainer.setPadding(0,
- layoutLottieAnimationPadding, 0, 0);
- final ImageView progressView = udfpsEnrollView.findViewById(
- R.id.udfps_enroll_animation_fp_progress_view);
- progressView.setPadding(0, -(layoutLottieAnimationPadding),
- 0, layoutLottieAnimationPadding);
- final ImageView fingerprintView = udfpsEnrollView.findViewById(
- R.id.udfps_enroll_animation_fp_view);
- fingerprintView.setPadding(0, -layoutLottieAnimationPadding,
- 0, layoutLottieAnimationPadding);
+ // In the portrait mode, the title and lottie animation view may
+ // overlap when title needs three lines, so adding some paddings
+ // between them, and adjusting the fp progress view here accordingly.
+ final int layoutLottieAnimationPadding = (int) getResources()
+ .getDimension(R.dimen.udfps_lottie_padding_top);
+ portraitLayoutContainer.setPadding(0,
+ layoutLottieAnimationPadding, 0, 0);
+ final ImageView progressView = udfpsEnrollView.findViewById(
+ R.id.udfps_enroll_animation_fp_progress_view);
+ progressView.setPadding(0, -(layoutLottieAnimationPadding),
+ 0, layoutLottieAnimationPadding);
+ final ImageView fingerprintView = udfpsEnrollView.findViewById(
+ R.id.udfps_enroll_animation_fp_view);
+ fingerprintView.setPadding(0, -layoutLottieAnimationPadding,
+ 0, layoutLottieAnimationPadding);
- portraitLayoutContainer.addView(udfpsEnrollView);
- setOnHoverListener(false, layout, udfpsEnrollView);
- }
+ // TODO(b/260970216) Instead of hiding the description text view, we should
+ // make the header view scrollable if the text is too long.
+ // If description text view has overlap with udfps progress view, hide it.
+ View view = layout.getDescriptionTextView();
+ layout.getViewTreeObserver().addOnDrawListener(() -> {
+ if (view.getVisibility() == View.VISIBLE
+ && hasOverlap(view, udfpsEnrollView)) {
+ view.setVisibility(View.GONE);
+ }
+ });
+ setOnHoverListener(false, layout, udfpsEnrollView);
setContentView(layout);
break;
case Surface.ROTATION_270:
default:
- if (FeatureFlagUtils.isEnabled(getApplicationContext(),
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS)) {
- final UdfpsEnrollView udfpsEnrollView = addUdfpsEnrollView(props.get(0));
- layout.addView(udfpsEnrollView);
- setOnHoverListener(true, layout, udfpsEnrollView);
- }
-
+ setOnHoverListener(true, layout, udfpsEnrollView);
setContentView(layout);
break;
}
@@ -1235,10 +1223,8 @@
}
}
- private UdfpsEnrollView addUdfpsEnrollView(FingerprintSensorPropertiesInternal udfpsProps) {
- UdfpsEnrollView udfpsEnrollView = (UdfpsEnrollView) getLayoutInflater().inflate(
- R.layout.udfps_enroll_view, null, false);
-
+ private UdfpsEnrollView updateUdfpsEnrollView(UdfpsEnrollView udfpsEnrollView,
+ FingerprintSensorPropertiesInternal udfpsProps) {
DisplayInfo displayInfo = new DisplayInfo();
getDisplay().getDisplayInfo(displayInfo);
mScaleFactor = mUdfpsUtils.getScaleFactor(displayInfo);
@@ -1305,6 +1291,24 @@
: R.id.sud_layout_content).setOnHoverListener(onHoverListener);
}
+
+ @VisibleForTesting boolean hasOverlap(View view1, View view2) {
+ int[] firstPosition = new int[2];
+ int[] secondPosition = new int[2];
+
+ view1.getLocationOnScreen(firstPosition);
+ view2.getLocationOnScreen(secondPosition);
+
+ // Rect constructor parameters: left, top, right, bottom
+ Rect rectView1 = new Rect(firstPosition[0], firstPosition[1],
+ firstPosition[0] + view1.getMeasuredWidth(),
+ firstPosition[1] + view1.getMeasuredHeight());
+ Rect rectView2 = new Rect(secondPosition[0], secondPosition[1],
+ secondPosition[0] + view2.getMeasuredWidth(),
+ secondPosition[1] + view2.getMeasuredHeight());
+ return rectView1.intersect(rectView2);
+ }
+
public static class IconTouchDialog extends InstrumentedDialogFragment {
@Override
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index e0f402b..be090e3 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -185,7 +185,8 @@
private static final int MSG_FINGER_AUTH_HELP = 1004;
private static final int CONFIRM_REQUEST = 101;
- private static final int CHOOSE_LOCK_GENERIC_REQUEST = 102;
+ @VisibleForTesting
+ static final int CHOOSE_LOCK_GENERIC_REQUEST = 102;
@VisibleForTesting
static final int ADD_FINGERPRINT_REQUEST = 10;
private static final int AUTO_ADD_FIRST_FINGERPRINT_REQUEST = 11;
@@ -1014,7 +1015,7 @@
true);
intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_REQUEST_GK_PW_HANDLE, true);
- intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST);
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java
index 6e42059..5ded91e 100644
--- a/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java
+++ b/src/com/android/settings/biometrics/fingerprint/UdfpsEnrollView.java
@@ -161,22 +161,20 @@
MarginLayoutParams marginLayoutParams = (MarginLayoutParams) getLayoutParams();
FrameLayout.LayoutParams params = (LayoutParams) getLayoutParams();
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
- parentView.getViewTreeObserver().addOnDrawListener(() -> {
- final int[] coords = parentView.getLocationOnScreen();
- final int parentLeft = coords[0];
- final int parentTop = coords[1];
- final int parentRight = parentLeft + parentView.getWidth();
- params.gravity = Gravity.RIGHT | Gravity.TOP;
- final int rightMargin = parentRight - rotatedBounds.right - getPaddingX();
- final int topMargin = rotatedBounds.top - parentTop - getPaddingY();
- if (marginLayoutParams.rightMargin == rightMargin
- && marginLayoutParams.topMargin == topMargin) {
- return;
- }
- marginLayoutParams.rightMargin = rightMargin;
- marginLayoutParams.topMargin = topMargin;
- setLayoutParams(params);
- });
+ final int[] coords = parentView.getLocationOnScreen();
+ final int parentLeft = coords[0];
+ final int parentTop = coords[1];
+ final int parentRight = parentLeft + parentView.getWidth();
+ params.gravity = Gravity.RIGHT | Gravity.TOP;
+ final int rightMargin = parentRight - rotatedBounds.right - getPaddingX();
+ final int topMargin = rotatedBounds.top - parentTop - getPaddingY();
+ if (marginLayoutParams.rightMargin == rightMargin
+ && marginLayoutParams.topMargin == topMargin) {
+ return;
+ }
+ marginLayoutParams.rightMargin = rightMargin;
+ marginLayoutParams.topMargin = topMargin;
+ setLayoutParams(params);
} else {
final int[] coords = parentView.getLocationOnScreen();
final int parentLeft = coords[0];
diff --git a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
index 4679eb2..ebaa2fa 100644
--- a/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
+++ b/src/com/android/settings/bluetooth/AdvancedBluetoothDetailsHeaderController.java
@@ -100,8 +100,6 @@
@VisibleForTesting
Handler mHandler = new Handler(Looper.getMainLooper());
@VisibleForTesting
- boolean mIsRegisterCallback = false;
- @VisibleForTesting
boolean mIsLeftDeviceEstimateReady;
@VisibleForTesting
boolean mIsRightDeviceEstimateReady;
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingController.java b/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingController.java
deleted file mode 100644
index 91221a3..0000000
--- a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingController.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.settings.bluetooth;
-
-import static com.android.settings.bluetooth.BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.util.FeatureFlagUtils;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceFragmentCompat;
-import androidx.preference.PreferenceScreen;
-
-import com.android.settings.R;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.core.lifecycle.Lifecycle;
-
-/**
- * The controller of the audio routing in the bluetooth detail settings.
- */
-public class BluetoothDetailsAudioRoutingController extends BluetoothDetailsController {
-
- private static final String KEY_DEVICE_CONTROLS_SPECIFIC_GROUP = "device_controls_specific";
- @VisibleForTesting
- static final String KEY_AUDIO_ROUTING = "audio_routing";
-
- public BluetoothDetailsAudioRoutingController(Context context,
- PreferenceFragmentCompat fragment, CachedBluetoothDevice device, Lifecycle lifecycle) {
- super(context, fragment, device, lifecycle);
- }
-
- @Override
- public boolean isAvailable() {
- return mCachedDevice.isHearingAidDevice() && FeatureFlagUtils.isEnabled(mContext,
- FeatureFlagUtils.SETTINGS_AUDIO_ROUTING);
- }
-
- @Override
- protected void init(PreferenceScreen screen) {
- if (!mCachedDevice.isHearingAidDevice()) {
- return;
- }
-
- final PreferenceCategory prefCategory = screen.findPreference(getPreferenceKey());
- final Preference pref = createAudioRoutingPreference(prefCategory.getContext());
- prefCategory.addPreference(pref);
- }
-
- @Override
- protected void refresh() {}
-
- @Override
- public String getPreferenceKey() {
- return KEY_DEVICE_CONTROLS_SPECIFIC_GROUP;
- }
-
- private Preference createAudioRoutingPreference(Context context) {
- final Preference preference = new Preference(context);
-
- preference.setKey(KEY_AUDIO_ROUTING);
- preference.setTitle(context.getString(R.string.bluetooth_audio_routing_title));
- preference.setSummary(context.getString(R.string.bluetooth_audio_routing_summary));
- final Bundle extras = preference.getExtras();
- extras.putString(KEY_DEVICE_ADDRESS, mCachedDevice.getAddress());
- preference.setFragment(BluetoothDetailsAudioRoutingFragment.class.getName());
-
- return preference;
- }
-}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java b/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java
deleted file mode 100644
index 6c435a2..0000000
--- a/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragment.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.settings.bluetooth;
-
-import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
-
-import static com.android.settings.bluetooth.BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS;
-
-import android.app.settings.SettingsEnums;
-import android.bluetooth.BluetoothDevice;
-import android.content.Context;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-
-import com.android.settings.R;
-import com.android.settings.dashboard.RestrictedDashboardFragment;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-
-/** Settings fragment containing bluetooth audio routing. */
-public class BluetoothDetailsAudioRoutingFragment extends RestrictedDashboardFragment {
-
- public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider(R.xml.bluetooth_audio_routing_fragment);
- private static final String TAG = "BluetoothDetailsAudioRoutingFragment";
- @VisibleForTesting
- CachedBluetoothDevice mCachedDevice;
-
- public BluetoothDetailsAudioRoutingFragment() {
- super(DISALLOW_CONFIG_BLUETOOTH);
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- final LocalBluetoothManager localBtMgr = Utils.getLocalBtManager(context);
- final CachedBluetoothDeviceManager cachedDeviceMgr = localBtMgr.getCachedDeviceManager();
- final BluetoothDevice bluetoothDevice = localBtMgr.getBluetoothAdapter().getRemoteDevice(
- getArguments().getString(KEY_DEVICE_ADDRESS));
-
- mCachedDevice = cachedDeviceMgr.findDevice(bluetoothDevice);
- if (mCachedDevice == null) {
- // Close this page if device is null with invalid device mac address
- Log.w(TAG, "onAttach() CachedDevice is null! Can not find address: "
- + bluetoothDevice.getAnonymizedAddress());
- finish();
- return;
- }
-
- use(HearingDeviceRingtoneRoutingPreferenceController.class).init(mCachedDevice);
- use(HearingDeviceCallRoutingPreferenceController.class).init(mCachedDevice);
- use(HearingDeviceMediaRoutingPreferenceController.class).init(mCachedDevice);
- use(HearingDeviceSystemSoundsRoutingPreferenceController.class).init(mCachedDevice);
- }
-
- @Override
- public int getMetricsCategory() {
- return SettingsEnums.BLUETOOTH_AUDIO_ROUTING;
- }
-
- @Override
- protected int getPreferenceScreenResId() {
- return R.xml.bluetooth_audio_routing_fragment;
- }
-
- @Override
- protected String getLogTag() {
- return TAG;
- }
-}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
index a3b1105..c4a4221 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
@@ -34,7 +34,7 @@
import com.google.common.annotations.VisibleForTesting;
/**
- * The controller of the hearing device controls in the bluetooth detail settings.
+ * The controller of the hearing device settings to launch Hearing device page.
*/
public class BluetoothDetailsHearingDeviceControlsController extends BluetoothDetailsController
implements Preference.OnPreferenceClickListener {
@@ -87,6 +87,7 @@
final Preference preference = new Preference(context);
preference.setKey(KEY_HEARING_DEVICE_CONTROLS);
preference.setTitle(context.getString(R.string.bluetooth_device_controls_title));
+ preference.setSummary(context.getString(R.string.bluetooth_device_controls_summary));
preference.setOnPreferenceClickListener(this);
return preference;
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index 208fba7..d0fb16a 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -120,6 +120,10 @@
pref.setTitle(profile.getNameResource(mCachedDevice.getDevice()));
pref.setOnPreferenceClickListener(this);
pref.setOrder(profile.getOrdinal());
+
+ if (profile instanceof LeAudioProfile) {
+ pref.setSummary(R.string.device_details_leaudio_toggle_summary);
+ }
return pref;
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 2a94b1e..99f3e31 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -314,8 +314,6 @@
lifecycle));
controllers.add(new BluetoothDetailsHearingDeviceControlsController(context, this,
mCachedDevice, lifecycle));
- controllers.add(new BluetoothDetailsAudioRoutingController(context, this, mCachedDevice,
- lifecycle));
}
return controllers;
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
index 17c5f36..2935c67 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
@@ -35,8 +35,10 @@
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
@@ -125,7 +127,7 @@
update(cachedBluetoothDevice);
}
} else {
- removeAllDevicesFromPreference();
+ removeAllDevicesFromPreference();
}
}
@@ -252,7 +254,7 @@
btPreference.setOnGearClickListener(mDeviceProfilesListener);
if (this instanceof Preference.OnPreferenceClickListener) {
btPreference.setOnPreferenceClickListener(
- (Preference.OnPreferenceClickListener)this);
+ (Preference.OnPreferenceClickListener) this);
}
mPreferenceMap.put(device, btPreference);
mDevicePreferenceCallback.onDeviceAdded(btPreference);
@@ -266,17 +268,20 @@
final BluetoothDevice device = cachedDevice.getDevice();
final CachedBluetoothDevice subCachedDevice = cachedDevice.getSubDevice();
if (mPreferenceMap.containsKey(device)) {
- mDevicePreferenceCallback.onDeviceRemoved(mPreferenceMap.get(device));
- mPreferenceMap.remove(device);
+ removePreference(device);
} else if (subCachedDevice != null) {
// When doing remove, to check if preference maps to sub device.
// This would happen when connection state is changed in detail page that there is no
// callback from SettingsLib.
final BluetoothDevice subDevice = subCachedDevice.getDevice();
- if (mPreferenceMap.containsKey(subDevice)) {
- mDevicePreferenceCallback.onDeviceRemoved(mPreferenceMap.get(subDevice));
- mPreferenceMap.remove(subDevice);
- }
+ removePreference(subDevice);
+ }
+ }
+
+ private void removePreference(BluetoothDevice device) {
+ if (mPreferenceMap.containsKey(device)) {
+ mDevicePreferenceCallback.onDeviceRemoved(mPreferenceMap.get(device));
+ mPreferenceMap.remove(device);
}
}
@@ -324,14 +329,38 @@
* Update the attributes of {@link Preference}.
*/
public void refreshPreference() {
- for (Preference preference : mPreferenceMap.values()) {
- ((BluetoothDevicePreference) preference).onPreferenceAttributesChanged();
+ List<BluetoothDevice> removeList = new ArrayList<>();
+ mPreferenceMap.forEach((key, preference) -> {
+ if (isDeviceOfMapInCachedDevicesList(key)) {
+ ((BluetoothDevicePreference) preference).onPreferenceAttributesChanged();
+ } else {
+ // If the BluetoothDevice of preference is not in the CachedDevices List, then
+ // remove this preference.
+ removeList.add(key);
+ }
+ });
+
+ for (BluetoothDevice bluetoothDevice : removeList) {
+ Log.d(getLogTag(), "removePreference key: " + bluetoothDevice.getAnonymizedAddress());
+ removePreference(bluetoothDevice);
}
}
- protected boolean isDeviceInCachedDevicesList(CachedBluetoothDevice cachedDevice){
+ protected boolean isDeviceInCachedDevicesList(CachedBluetoothDevice cachedDevice) {
return mLocalManager.getCachedDeviceManager().getCachedDevicesCopy().contains(cachedDevice);
}
+
+ private boolean isDeviceOfMapInCachedDevicesList(BluetoothDevice inputBluetoothDevice) {
+ Collection<CachedBluetoothDevice> cachedDevices =
+ mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
+ if (cachedDevices == null || cachedDevices.isEmpty()) {
+ return false;
+ }
+ return cachedDevices.stream()
+ .anyMatch(cachedBluetoothDevice -> cachedBluetoothDevice.getDevice() != null
+ && cachedBluetoothDevice.getDevice().equals(inputBluetoothDevice));
+ }
+
protected String getLogTag() {
return TAG;
}
diff --git a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
index 522b5cb..a4a9891 100644
--- a/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
+++ b/src/com/android/settings/bluetooth/DeviceListPreferenceFragment.java
@@ -196,10 +196,11 @@
}
// Prevent updates while the list shows one of the state messages
- if (mBluetoothAdapter.getState() != BluetoothAdapter.STATE_ON) return;
+ if (mBluetoothAdapter.getState() != BluetoothAdapter.STATE_ON) {
+ return;
+ }
- if (mLeScanFilters != null
- || (mFilter != null && mFilter.matches(cachedDevice.getDevice()))) {
+ if (mFilter != null && mFilter.matches(cachedDevice.getDevice())) {
createDevicePreference(cachedDevice);
}
}
@@ -325,7 +326,12 @@
if (cachedDevice == null) {
cachedDevice = mCachedDeviceManager.addDevice(device);
}
- onDeviceAdded(cachedDevice);
+ // Only add device preference when it's not found in the map and there's no other
+ // state message showing in the list
+ if (mDevicePreferenceMap.get(cachedDevice) == null
+ && mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
+ createDevicePreference(cachedDevice);
+ }
}
@Override
diff --git a/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java b/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
index b9f3413..04252fa 100644
--- a/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
+++ b/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
@@ -48,6 +48,8 @@
private final DevelopmentSettingsDashboardFragment mFragment;
+ private final GraphicsDriverSystemPropertiesWrapper mSystemProperties;
+
@VisibleForTesting
static final String PROPERTY_RO_GFX_ANGLE_SUPPORTED = "ro.gfx.angle.supported";
@@ -57,11 +59,34 @@
@VisibleForTesting
static final String ANGLE_DRIVER_SUFFIX = "angle";
+ @VisibleForTesting
+ static class Injector {
+ public GraphicsDriverSystemPropertiesWrapper createSystemPropertiesWrapper() {
+ return new GraphicsDriverSystemPropertiesWrapper() {
+ @Override
+ public String get(String key, String def) {
+ return SystemProperties.get(key, def);
+ }
+
+ @Override
+ public void set(String key, String val) {
+ SystemProperties.set(key, val);
+ }
+ };
+ }
+ }
public GraphicsDriverEnableAngleAsSystemDriverController(
Context context, DevelopmentSettingsDashboardFragment fragment) {
+ this(context, fragment, new Injector());
+ }
+
+ @VisibleForTesting
+ GraphicsDriverEnableAngleAsSystemDriverController(
+ Context context, DevelopmentSettingsDashboardFragment fragment, Injector injector) {
super(context);
mFragment = fragment;
+ mSystemProperties = injector.createSystemPropertiesWrapper();
}
@Override
@@ -76,20 +101,27 @@
// set "persist.graphics.egl" to "" if enableAngleAsSystemDriver is false
GraphicsEnvironment.getInstance().toggleAngleAsSystemDriver(enableAngleAsSystemDriver);
// pop up a window asking user to reboot to make the new "persist.graphics.egl" take effect
+ showRebootDialog();
+ return true;
+ }
+
+ @VisibleForTesting
+ void showRebootDialog() {
RebootConfirmationDialogFragment.show(
mFragment, R.string.reboot_dialog_enable_angle_as_system_driver,
R.string.cancel, this);
- return true;
}
+
@Override
public void updateState(Preference preference) {
// set switch on if "persist.graphics.egl" is "angle" and angle is built in /vendor
// set switch off otherwise.
- final String currentGlesDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ final String currentGlesDriver =
+ mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
final boolean isAngle = TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver);
- final boolean isAngleSupported =
- TextUtils.equals(SystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED), "true");
+ final boolean isAngleSupported = TextUtils
+ .equals(mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
((SwitchPreference) mPreference).setChecked(isAngle && isAngleSupported);
((SwitchPreference) mPreference).setEnabled(isAngleSupported);
}
@@ -98,8 +130,8 @@
protected void onDeveloperOptionsSwitchEnabled() {
// only enable the switch if ro.gfx.angle.supported is true
// we use ro.gfx.angle.supported to indicate if ANGLE libs are installed under /vendor
- final boolean isAngleSupported =
- TextUtils.equals(SystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED), "true");
+ final boolean isAngleSupported = TextUtils
+ .equals(mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
((SwitchPreference) mPreference).setEnabled(isAngleSupported);
}
@@ -116,7 +148,8 @@
@Override
public void onRebootCancelled() {
// if user presses button "Cancel", do not reboot the device, and toggles switch back
- final String currentGlesDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ final String currentGlesDriver =
+ mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
if (TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver)) {
// if persist.graphics.egl = "angle", set the property value back to ""
GraphicsEnvironment.getInstance().toggleAngleAsSystemDriver(false);
diff --git a/src/com/android/settings/development/graphicsdriver/GraphicsDriverSystemPropertiesWrapper.java b/src/com/android/settings/development/graphicsdriver/GraphicsDriverSystemPropertiesWrapper.java
new file mode 100644
index 0000000..549cd81
--- /dev/null
+++ b/src/com/android/settings/development/graphicsdriver/GraphicsDriverSystemPropertiesWrapper.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+package com.android.settings.development.graphicsdriver;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.SystemProperties;
+/**
+ * Wrapper interface to access {@link SystemProperties}.
+ *
+ * @hide
+ */
+interface GraphicsDriverSystemPropertiesWrapper {
+ /**
+ * Get the String value for the given {@code key}.
+ *
+ * @param key the key to lookup
+ * @param def the default value in case the property is not set or empty
+ * @return if the {@code key} isn't found, return {@code def} if it isn't null, or an empty
+ * string otherwise
+ */
+ @NonNull
+ String get(@NonNull String key, @Nullable String def);
+ /**
+ * Set the value for the given {@code key} to {@code val}.
+ *
+ * @throws IllegalArgumentException if the {@code val} exceeds 91 characters
+ * @throws RuntimeException if the property cannot be set, for example, if it was blocked by
+ * SELinux. libc will log the underlying reason.
+ */
+ void set(@NonNull String key, @Nullable String val);
+}
diff --git a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
index 777e428..79e0194 100644
--- a/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
+++ b/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetail.java
@@ -343,7 +343,7 @@
final String stateString;
final String footerString;
- if (!mBatteryOptimizeUtils.isValidPackageName()) {
+ if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
// Present optimized only string when the package name is invalid.
stateString = context.getString(R.string.manager_battery_usage_optimized_only);
footerString = context.getString(
diff --git a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
index 0558d46..eb4bbf6 100644
--- a/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
+++ b/src/com/android/settings/fuelgauge/BatteryBackupHelper.java
@@ -22,6 +22,7 @@
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupHelper;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.os.IDeviceIdleController;
@@ -34,9 +35,11 @@
import androidx.annotation.VisibleForTesting;
+import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
import java.io.IOException;
+import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
@@ -47,10 +50,11 @@
/** An inditifier for {@link BackupHelper}. */
public static final String TAG = "BatteryBackupHelper";
private static final String DEVICE_IDLE_SERVICE = "deviceidle";
+ private static final String BATTERY_OPTIMIZE_BACKUP_FILE_NAME =
+ "battery_optimize_backup_historical_logs";
static final String DELIMITER = ",";
static final String DELIMITER_MODE = ":";
- static final String KEY_FULL_POWER_LIST = "full_power_list";
static final String KEY_OPTIMIZATION_LIST = "optimization_mode_list";
@VisibleForTesting
@@ -78,7 +82,7 @@
Log.w(TAG, "ignore performBackup() for non-owner or empty data");
return;
}
- final List<String> allowlistedApps = backupFullPowerList(data);
+ final List<String> allowlistedApps = getFullPowerList();
if (allowlistedApps != null) {
backupOptimizationMode(data, allowlistedApps);
}
@@ -86,11 +90,12 @@
@Override
public void restoreEntity(BackupDataInputStream data) {
- BatterySettingsMigrateChecker.verifyConfiguration(mContext);
+ BatterySettingsMigrateChecker.verifySaverConfiguration(mContext);
if (!isOwner() || data == null || data.size() == 0) {
Log.w(TAG, "ignore restoreEntity() for non-owner or empty data");
return;
}
+
if (KEY_OPTIMIZATION_LIST.equals(data.getKey())) {
final int dataSize = data.size();
final byte[] dataBytes = new byte[dataSize];
@@ -100,7 +105,10 @@
Log.e(TAG, "failed to load BackupDataInputStream", e);
return;
}
- restoreOptimizationMode(dataBytes);
+ final int restoreCount = restoreOptimizationMode(dataBytes);
+ if (restoreCount > 0) {
+ BatterySettingsMigrateChecker.verifyOptimizationModes(mContext);
+ }
}
}
@@ -108,7 +116,7 @@
public void writeNewStateDescription(ParcelFileDescriptor newState) {
}
- private List<String> backupFullPowerList(BackupDataOutput data) {
+ private List<String> getFullPowerList() {
final long timestamp = System.currentTimeMillis();
String[] allowlistedApps;
try {
@@ -122,10 +130,7 @@
Log.w(TAG, "no data found in the getFullPowerList()");
return new ArrayList<>();
}
-
- final String allowedApps = String.join(DELIMITER, allowlistedApps);
- writeBackupData(data, KEY_FULL_POWER_LIST, allowedApps);
- Log.d(TAG, String.format("backup getFullPowerList() size=%d in %d/ms",
+ Log.d(TAG, String.format("getFullPowerList() size=%d in %d/ms",
allowlistedApps.length, (System.currentTimeMillis() - timestamp)));
return Arrays.asList(allowlistedApps);
}
@@ -141,6 +146,7 @@
int backupCount = 0;
final StringBuilder builder = new StringBuilder();
final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+ final SharedPreferences sharedPreferences = getSharedPreferences(mContext);
// Converts application into the AppUsageState.
for (ApplicationInfo info : applications) {
final int mode = BatteryOptimizeUtils.getMode(appOps, info.uid, info.packageName);
@@ -157,6 +163,9 @@
info.packageName + DELIMITER_MODE + optimizationMode;
builder.append(packageOptimizeMode + DELIMITER);
Log.d(TAG, "backupOptimizationMode: " + packageOptimizeMode);
+ BatteryHistoricalLogUtil.writeLog(
+ sharedPreferences, Action.BACKUP, info.packageName,
+ /* actionDescription */ "mode: " + optimizationMode);
backupCount++;
}
@@ -166,17 +175,17 @@
}
@VisibleForTesting
- void restoreOptimizationMode(byte[] dataBytes) {
+ int restoreOptimizationMode(byte[] dataBytes) {
final long timestamp = System.currentTimeMillis();
final String dataContent = new String(dataBytes, StandardCharsets.UTF_8);
if (dataContent == null || dataContent.isEmpty()) {
Log.w(TAG, "no data found in the restoreOptimizationMode()");
- return;
+ return 0;
}
final String[] appConfigurations = dataContent.split(BatteryBackupHelper.DELIMITER);
if (appConfigurations == null || appConfigurations.length == 0) {
Log.w(TAG, "no data found from the split() processing");
- return;
+ return 0;
}
int restoreCount = 0;
for (int index = 0; index < appConfigurations.length; index++) {
@@ -208,18 +217,45 @@
}
Log.d(TAG, String.format("restoreOptimizationMode() count=%d in %d/ms",
restoreCount, (System.currentTimeMillis() - timestamp)));
+ return restoreCount;
+ }
+
+ /** Dump the app optimization mode backup history data. */
+ public static void dumpHistoricalData(Context context, PrintWriter writer) {
+ BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(
+ getSharedPreferences(context), writer);
+ }
+
+ static boolean isOwner() {
+ return UserHandle.myUserId() == UserHandle.USER_SYSTEM;
+ }
+
+ static BatteryOptimizeUtils newBatteryOptimizeUtils(
+ Context context, String packageName, BatteryOptimizeUtils testOptimizeUtils) {
+ final int uid = BatteryUtils.getInstance(context).getPackageUid(packageName);
+ if (uid == BatteryUtils.UID_NULL) {
+ return null;
+ }
+ final BatteryOptimizeUtils batteryOptimizeUtils =
+ testOptimizeUtils != null
+ ? testOptimizeUtils /*testing only*/
+ : new BatteryOptimizeUtils(context, uid, packageName);
+ return batteryOptimizeUtils;
+ }
+
+ @VisibleForTesting
+ static SharedPreferences getSharedPreferences(Context context) {
+ return context.getSharedPreferences(
+ BATTERY_OPTIMIZE_BACKUP_FILE_NAME, Context.MODE_PRIVATE);
}
private void restoreOptimizationMode(
String packageName, @BatteryOptimizeUtils.OptimizationMode int mode) {
- final int uid = BatteryUtils.getInstance(mContext).getPackageUid(packageName);
- if (uid == BatteryUtils.UID_NULL) {
+ final BatteryOptimizeUtils batteryOptimizeUtils =
+ newBatteryOptimizeUtils(mContext, packageName, mBatteryOptimizeUtils);
+ if (batteryOptimizeUtils == null) {
return;
}
- final BatteryOptimizeUtils batteryOptimizeUtils =
- mBatteryOptimizeUtils != null
- ? mBatteryOptimizeUtils /*testing only*/
- : new BatteryOptimizeUtils(mContext, uid, packageName);
batteryOptimizeUtils.setAppUsageState(
mode, BatteryOptimizeHistoricalLogEntry.Action.RESTORE);
Log.d(TAG, String.format("restore:%s mode=%d", packageName, mode));
@@ -273,8 +309,4 @@
Log.e(TAG, "writeBackupData() is failed for " + dataKey, e);
}
}
-
- private static boolean isOwner() {
- return UserHandle.myUserId() == UserHandle.USER_SYSTEM;
- }
}
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index 81a15ca..79ecd40 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -34,24 +34,20 @@
import java.lang.annotation.RetentionPolicy;
/**
- * Use this broadcastReceiver to listen to the battery change, and it will invoke
- * {@link OnBatteryChangedListener} if any of the following has been changed:
- *
- * 1. Battery level(e.g. 100%->99%)
- * 2. Battery status(e.g. plugged->unplugged)
- * 3. Battery saver(e.g. off->on)
- * 4. Battery health(e.g. good->overheat)
+ * Use this broadcastReceiver to listen to the battery change and it will invoke
+ * {@link OnBatteryChangedListener}
*/
public class BatteryBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "BatteryBroadcastRcvr";
/**
- * Callback when the following has been changed:
+ * Callback if any of the monitored fields has been changed:
*
* Battery level(e.g. 100%->99%)
* Battery status(e.g. plugged->unplugged)
* Battery saver(e.g. off->on)
* Battery health(e.g. good->overheat)
+ * Battery charging status(e.g. default->long life)
*/
public interface OnBatteryChangedListener {
void onBatteryChanged(@BatteryUpdateType int type);
@@ -63,6 +59,7 @@
BatteryUpdateType.BATTERY_SAVER,
BatteryUpdateType.BATTERY_STATUS,
BatteryUpdateType.BATTERY_HEALTH,
+ BatteryUpdateType.CHARGING_STATUS,
BatteryUpdateType.BATTERY_NOT_PRESENT})
public @interface BatteryUpdateType {
int MANUAL = 0;
@@ -70,7 +67,8 @@
int BATTERY_SAVER = 2;
int BATTERY_STATUS = 3;
int BATTERY_HEALTH = 4;
- int BATTERY_NOT_PRESENT = 5;
+ int CHARGING_STATUS = 5;
+ int BATTERY_NOT_PRESENT = 6;
}
@VisibleForTesting
@@ -78,6 +76,8 @@
@VisibleForTesting
String mBatteryStatus;
@VisibleForTesting
+ int mChargingStatus;
+ @VisibleForTesting
int mBatteryHealth;
private OnBatteryChangedListener mBatteryListener;
private Context mContext;
@@ -121,21 +121,27 @@
final String batteryLevel = Utils.getBatteryPercentage(intent);
final String batteryStatus =
Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false);
+ final int chargingStatus = intent.getIntExtra(
+ BatteryManager.EXTRA_CHARGING_STATUS, BatteryManager.CHARGING_POLICY_DEFAULT);
final int batteryHealth = intent.getIntExtra(
BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
Log.d(
TAG,
- "Battery changed: level="
+ "Battery changed: level: "
+ batteryLevel
- + ", status="
+ + "| status: "
+ batteryStatus
- + ", health="
+ + "| chargingStatus: "
+ + chargingStatus
+ + "| health: "
+ batteryHealth);
if (!Utils.isBatteryPresent(intent)) {
Log.w(TAG, "Problem reading the battery meter.");
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_NOT_PRESENT);
} else if (forceUpdate) {
mBatteryListener.onBatteryChanged(BatteryUpdateType.MANUAL);
+ } else if (chargingStatus != mChargingStatus) {
+ mBatteryListener.onBatteryChanged(BatteryUpdateType.CHARGING_STATUS);
} else if (batteryHealth != mBatteryHealth) {
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_HEALTH);
} else if(!batteryLevel.equals(mBatteryLevel)) {
@@ -145,6 +151,7 @@
}
mBatteryLevel = batteryLevel;
mBatteryStatus = batteryStatus;
+ mChargingStatus = chargingStatus;
mBatteryHealth = batteryHealth;
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
diff --git a/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java b/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java
index a827e6d..f82b703 100644
--- a/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java
+++ b/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtil.java
@@ -37,40 +37,40 @@
@VisibleForTesting
static final int MAX_ENTRIES = 40;
- /**
- * Writes a log entry.
- *
- * <p>Keeps up to {@link #MAX_ENTRIES} in the log, once that number is exceeded, it prunes the
- * oldest one.
- */
- static void writeLog(Context context, Action action, String pkg, String actionDescription) {
+ /** Writes a log entry for battery optimization mode. */
+ static void writeLog(
+ Context context, Action action, String packageName, String actionDescription) {
+ writeLog(getSharedPreferences(context), action, packageName, actionDescription);
+ }
+
+ static void writeLog(SharedPreferences sharedPreferences, Action action,
+ String packageName, String actionDescription) {
writeLog(
- context,
+ sharedPreferences,
BatteryOptimizeHistoricalLogEntry.newBuilder()
- .setPackageName(pkg)
+ .setPackageName(packageName)
.setAction(action)
.setActionDescription(actionDescription)
.setTimestamp(System.currentTimeMillis())
.build());
}
- private static void writeLog(Context context, BatteryOptimizeHistoricalLogEntry logEntry) {
- SharedPreferences sharedPreferences = getSharedPreferences(context);
-
+ private static void writeLog(
+ SharedPreferences sharedPreferences, BatteryOptimizeHistoricalLogEntry logEntry) {
BatteryOptimizeHistoricalLog existingLog =
parseLogFromString(sharedPreferences.getString(LOGS_KEY, ""));
BatteryOptimizeHistoricalLog.Builder newLogBuilder = existingLog.toBuilder();
- // Prune old entries
+ // Prune old entries to limit the max logging data count.
if (existingLog.getLogEntryCount() >= MAX_ENTRIES) {
newLogBuilder.removeLogEntry(0);
}
newLogBuilder.addLogEntry(logEntry);
+ String loggingContent =
+ Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT);
sharedPreferences
.edit()
- .putString(
- LOGS_KEY,
- Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT))
+ .putString(LOGS_KEY, loggingContent)
.apply();
}
@@ -79,34 +79,36 @@
storedLogs, BatteryOptimizeHistoricalLog.getDefaultInstance());
}
- /**
- * Prints the historical log that has previously been stored by this utility.
- */
+ /** Prints the historical log that has previously been stored by this utility. */
public static void printBatteryOptimizeHistoricalLog(Context context, PrintWriter writer) {
+ printBatteryOptimizeHistoricalLog(getSharedPreferences(context), writer);
+ }
+
+ /** Prints the historical log that has previously been stored by this utility. */
+ public static void printBatteryOptimizeHistoricalLog(
+ SharedPreferences sharedPreferences, PrintWriter writer) {
writer.println("Battery optimize state history:");
- SharedPreferences sharedPreferences = getSharedPreferences(context);
BatteryOptimizeHistoricalLog existingLog =
parseLogFromString(sharedPreferences.getString(LOGS_KEY, ""));
List<BatteryOptimizeHistoricalLogEntry> logEntryList = existingLog.getLogEntryList();
if (logEntryList.isEmpty()) {
- writer.println("\tNo past logs.");
+ writer.println("\tnothing to dump");
} else {
- writer.println("0:RESTRICTED 1:UNRESTRICTED 2:OPTIMIZED 3:UNKNOWN");
+ writer.println("0:UNKNOWN 1:RESTRICTED 2:UNRESTRICTED 3:OPTIMIZED");
logEntryList.forEach(entry -> writer.println(toString(entry)));
}
}
- /**
- * Gets the unique key for logging, combined with package name, delimiter and user id.
- */
- static String getPackageNameWithUserId(String pkgName, int userId) {
- return pkgName + ":" + userId;
+ /** Gets the unique key for logging. */
+ static String getPackageNameWithUserId(String packageName, int userId) {
+ return packageName + ":" + userId;
}
private static String toString(BatteryOptimizeHistoricalLogEntry entry) {
- return String.format("%s\tAction:%s\tEvent:%s\tTimestamp:%s", entry.getPackageName(),
- entry.getAction(), entry.getActionDescription(),
- ConvertUtils.utcToLocalTimeForLogging(entry.getTimestamp()));
+ return String.format("%s\t%s\taction:%s\tevent:%s",
+ ConvertUtils.utcToLocalTimeForLogging(entry.getTimestamp()),
+ entry.getPackageName(), entry.getAction(),
+ entry.getActionDescription());
}
@VisibleForTesting
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index d164e93..27d7154 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -51,7 +51,7 @@
public int batteryStatus;
public int pluggedStatus;
public boolean discharging = true;
- public boolean isOverheated;
+ public boolean isBatteryDefender;
public long remainingTimeUs = 0;
public long averageTimeToDischarge = EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN;
public String batteryPercentString;
@@ -257,9 +257,9 @@
info.pluggedStatus = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
info.mCharging = info.pluggedStatus != 0;
info.averageTimeToDischarge = estimate.getAverageDischargeTime();
- info.isOverheated = batteryBroadcast.getIntExtra(
- BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN)
- == BatteryManager.BATTERY_HEALTH_OVERHEAT;
+ info.isBatteryDefender = batteryBroadcast.getIntExtra(
+ BatteryManager.EXTRA_CHARGING_STATUS, BatteryManager.CHARGING_POLICY_DEFAULT)
+ == BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE;
info.statusLabel = Utils.getBatteryStatus(context, batteryBroadcast, isCompactStatus);
info.batteryStatus = batteryBroadcast.getIntExtra(
@@ -283,7 +283,7 @@
info.discharging = false;
info.suggestionLabel = null;
int dockDefenderMode = BatteryUtils.getCurrentDockDefenderMode(context, info);
- if ((info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL
+ if ((info.isBatteryDefender && status != BatteryManager.BATTERY_STATUS_FULL
&& dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
|| dockDefenderMode == BatteryUtils.DockDefenderMode.ACTIVE) {
// Battery defender active, battery charging paused
@@ -299,9 +299,10 @@
(double) PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */,
true /* collapseTimeUnit */);
int resId = R.string.power_charging_duration;
- info.remainingLabel = context.getString(R.string.power_remaining_charging_duration_only,
- timeString);
- info.chargeLabel = context.getString(resId, info.batteryPercentString, timeString);
+ info.remainingLabel = chargeTimeMs <= 0 ? null : context.getString(
+ R.string.power_remaining_charging_duration_only, timeString);
+ info.chargeLabel = chargeTimeMs <= 0 ? info.batteryPercentString
+ : context.getString(resId, info.batteryPercentString, timeString);
} else if (dockDefenderMode == BatteryUtils.DockDefenderMode.FUTURE_BYPASS) {
// Dock defender will be triggered in the future, charging will be optimized.
info.chargeLabel = context.getString(R.string.power_charging_future_paused,
@@ -321,18 +322,11 @@
final long drainTimeUs = PowerUtil.convertMsToUs(estimate.getEstimateMillis());
if (drainTimeUs > 0) {
info.remainingTimeUs = drainTimeUs;
- info.remainingLabel = PowerUtil.getBatteryRemainingStringFormatted(
+ info.remainingLabel = PowerUtil.getBatteryRemainingShortStringFormatted(
context,
- PowerUtil.convertUsToMs(drainTimeUs),
- null /* percentageString */,
- false /* basedOnUsage */
+ PowerUtil.convertUsToMs(drainTimeUs)
);
- info.chargeLabel = PowerUtil.getBatteryRemainingStringFormatted(
- context,
- PowerUtil.convertUsToMs(drainTimeUs),
- info.batteryPercentString,
- estimate.isBasedOnUsage() && !shortString
- );
+ info.chargeLabel = info.remainingLabel;
info.suggestionLabel = PowerUtil.getBatteryTipStringFormatted(
context, PowerUtil.convertUsToMs(drainTimeUs));
} else {
diff --git a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
index b9ac64d..589e1fd 100644
--- a/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryOptimizeUtils.java
@@ -31,11 +31,14 @@
import androidx.annotation.VisibleForTesting;
+import com.android.settings.R;
import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.List;
/** A utility class for application usage operation. */
public class BatteryOptimizeUtils {
@@ -125,11 +128,10 @@
mContext, mode, mUid, mPackageName, mBatteryUtils, mPowerAllowListBackend, action);
}
- /**
- * Return {@code true} if package name is valid (can get an uid).
- */
- public boolean isValidPackageName() {
- return mBatteryUtils.getPackageUid(mPackageName) != BatteryUtils.UID_NULL;
+ /** Return {@code true} if it is disabled for default optimized mode only. */
+ public boolean isDisabledForOptimizeModeOnly() {
+ return getAllowList(mContext).contains(mPackageName)
+ || mBatteryUtils.getPackageUid(mPackageName) == BatteryUtils.UID_NULL;
}
/**
@@ -214,6 +216,11 @@
|| powerAllowlistBackend.isDefaultActiveApp(packageName, uid);
}
+ static List<String> getAllowList(Context context) {
+ return Arrays.asList(context.getResources().getStringArray(
+ R.array.config_disable_optimization_mode_apps));
+ }
+
private static void setAppUsageStateInternal(
Context context, @OptimizationMode int mode, int uid, String packageName,
BatteryUtils batteryUtils, PowerAllowlistBackend powerAllowlistBackend,
diff --git a/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java b/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java
index c54e6d8..4b9e6ef 100644
--- a/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java
+++ b/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java
@@ -23,16 +23,27 @@
import android.provider.Settings;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.settings.R;
+import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry;
import com.android.settings.fuelgauge.batterysaver.BatterySaverScheduleRadioButtonsController;
import com.android.settingslib.fuelgauge.BatterySaverUtils;
+import java.util.List;
+
/** Execute battery settings migration tasks in the device booting stage. */
public final class BatterySettingsMigrateChecker extends BroadcastReceiver {
private static final String TAG = "BatterySettingsMigrateChecker";
+ @VisibleForTesting
+ static BatteryOptimizeUtils sBatteryOptimizeUtils = null;
+
@Override
public void onReceive(Context context, Intent intent) {
- if (intent != null && Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+ if (intent != null
+ && Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())
+ && BatteryBackupHelper.isOwner()) {
verifyConfiguration(context);
}
}
@@ -40,9 +51,35 @@
static void verifyConfiguration(Context context) {
context = context.getApplicationContext();
verifySaverConfiguration(context);
+ verifyOptimizationModes(context);
}
- private static void verifySaverConfiguration(Context context) {
+ /** Avoid users set important apps into the unexpected battery optimize modes */
+ static void verifyOptimizationModes(Context context) {
+ Log.d(TAG, "invoke verifyOptimizationModes()");
+ verifyOptimizationModes(context, BatteryOptimizeUtils.getAllowList(context));
+ }
+
+ @VisibleForTesting
+ static void verifyOptimizationModes(Context context, List<String> allowList) {
+ allowList.forEach(packageName -> {
+ final BatteryOptimizeUtils batteryOptimizeUtils =
+ BatteryBackupHelper.newBatteryOptimizeUtils(context, packageName,
+ /* testOptimizeUtils */ sBatteryOptimizeUtils);
+ if (batteryOptimizeUtils == null) {
+ return;
+ }
+ if (batteryOptimizeUtils.getAppOptimizationMode() !=
+ BatteryOptimizeUtils.MODE_OPTIMIZED) {
+ Log.w(TAG, "Reset optimization mode for: " + packageName);
+ batteryOptimizeUtils.setAppUsageState(BatteryOptimizeUtils.MODE_OPTIMIZED,
+ BatteryOptimizeHistoricalLogEntry.Action.FORCE_RESET);
+ }
+ });
+ }
+
+ static void verifySaverConfiguration(Context context) {
+ Log.d(TAG, "invoke verifySaverConfiguration()");
final ContentResolver resolver = context.getContentResolver();
final int threshold = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index 72d84ef..12760b1 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -18,7 +18,6 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.InstallSourceInfo;
import android.content.pm.PackageInfo;
@@ -322,10 +321,10 @@
}
/**
- * Return {@code true} if battery is overheated and charging.
+ * Return {@code true} if battery defender is on and charging.
*/
public static boolean isBatteryDefenderOn(BatteryInfo batteryInfo) {
- return batteryInfo.isOverheated && !batteryInfo.discharging;
+ return batteryInfo.isBatteryDefender && !batteryInfo.discharging;
}
/**
@@ -627,11 +626,11 @@
if (Settings.Global.getInt(context.getContentResolver(),
SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0) == 1) {
return DockDefenderMode.TEMPORARILY_BYPASSED;
- } else if (batteryInfo.isOverheated && FeatureFactory.getFactory(context)
+ } else if (batteryInfo.isBatteryDefender && FeatureFactory.getFactory(context)
.getPowerUsageFeatureProvider(context)
.isExtraDefend()) {
return DockDefenderMode.ACTIVE;
- } else if (!batteryInfo.isOverheated) {
+ } else if (!batteryInfo.isBatteryDefender) {
return DockDefenderMode.FUTURE_BYPASS;
}
}
diff --git a/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java b/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java
index 88241b6..ca75b0e 100644
--- a/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/OptimizedPreferenceController.java
@@ -46,8 +46,8 @@
@Override
public void updateState(Preference preference) {
- if (!mBatteryOptimizeUtils.isValidPackageName()) {
- Log.d(TAG, "invalid package name, optimized states only");
+ if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
+ Log.d(TAG, "disable preference for " + mBatteryOptimizeUtils.getPackageName());
preference.setEnabled(true);
((SelectorWithWidgetPreference) preference).setChecked(true);
return;
diff --git a/src/com/android/settings/fuelgauge/RestrictedPreferenceController.java b/src/com/android/settings/fuelgauge/RestrictedPreferenceController.java
index fe896a6..7db77f1 100644
--- a/src/com/android/settings/fuelgauge/RestrictedPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/RestrictedPreferenceController.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package com.android.settings.fuelgauge;
import android.content.Context;
@@ -43,8 +42,8 @@
@Override
public void updateState(Preference preference) {
- if (!mBatteryOptimizeUtils.isValidPackageName()) {
- Log.d(TAG, "invalid package name, disable pref");
+ if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
+ Log.d(TAG, "disable preference for " + mBatteryOptimizeUtils.getPackageName());
preference.setEnabled(false);
return;
} else {
diff --git a/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java b/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java
index be4091c..4578723 100644
--- a/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/UnrestrictedPreferenceController.java
@@ -42,8 +42,8 @@
@Override
public void updateState(Preference preference) {
- if (!mBatteryOptimizeUtils.isValidPackageName()) {
- Log.d(TAG, "invalid package name, disable pref");
+ if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
+ Log.d(TAG, "disable preference for " + mBatteryOptimizeUtils.getPackageName());
preference.setEnabled(false);
return;
} else {
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
index 2dc057e..8b7d4c1 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
@@ -37,13 +37,12 @@
@Override
public BatteryTip detect() {
- final boolean isBasicBatteryDefend = mBatteryInfo.isOverheated
- && !FeatureFactory.getFactory(mContext)
- .getPowerUsageFeatureProvider(mContext)
- .isExtraDefend();
- final int state = isBasicBatteryDefend
- ? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE;
- final boolean isPluggedIn = mBatteryInfo.pluggedStatus != 0;
- return new BatteryDefenderTip(state, isPluggedIn);
+ final boolean isBasicBatteryDefend = mBatteryInfo.isBatteryDefender
+ && !FeatureFactory.getFactory(mContext).getPowerUsageFeatureProvider(mContext)
+ .isExtraDefend();
+ final int state = isBasicBatteryDefend
+ ? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE;
+ final boolean isPluggedIn = mBatteryInfo.pluggedStatus != 0;
+ return new BatteryDefenderTip(state, isPluggedIn);
}
}
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 03bc1b3..829a89c 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -57,7 +57,6 @@
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
-import androidx.window.embedding.ActivityEmbeddingController;
import androidx.window.embedding.SplitRule;
import com.android.settings.R;
@@ -108,7 +107,6 @@
private View mTwoPaneSuggestionView;
private CategoryMixin mCategoryMixin;
private Set<HomepageLoadedListener> mLoadedListeners;
- private ActivityEmbeddingController mActivityEmbeddingController;
private boolean mIsEmbeddingActivityEnabled;
private boolean mIsTwoPane;
// A regular layout shows icons on homepage, whereas a simplified layout doesn't.
@@ -200,8 +198,7 @@
setupEdgeToEdge();
setContentView(R.layout.settings_homepage_container);
- mActivityEmbeddingController = ActivityEmbeddingController.getInstance(this);
- mIsTwoPane = mActivityEmbeddingController.isActivityEmbedded(this);
+ mIsTwoPane = ActivityEmbeddingUtils.isAlreadyEmbedded(this);
updateAppBarMinHeight();
initHomepageContainer();
@@ -242,7 +239,7 @@
// Settings app may be launched on an existing task. Reset SplitPairRule of SubSettings here
// to prevent SplitPairRule of an existing task applied on a new started Settings app.
- if (ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this)
+ if (mIsEmbeddingActivityEnabled
&& (getIntent().getFlags() & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
initSplitPairRules();
}
@@ -284,7 +281,7 @@
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- final boolean newTwoPaneState = mActivityEmbeddingController.isActivityEmbedded(this);
+ final boolean newTwoPaneState = ActivityEmbeddingUtils.isAlreadyEmbedded(this);
if (mIsTwoPane != newTwoPaneState) {
mIsTwoPane = newTwoPaneState;
updateHomepageAppBar();
@@ -427,8 +424,9 @@
}
private boolean shouldLaunchDeepLinkIntentToRight() {
- if (!FeatureFlagUtils.isEnabled(this, FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)
- || !ActivityEmbeddingUtils.isSettingsSplitEnabled(this)) {
+ if (!ActivityEmbeddingUtils.isSettingsSplitEnabled(this)
+ || !FeatureFlagUtils.isEnabled(this,
+ FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)) {
return false;
}
diff --git a/src/com/android/settings/localepicker/LocaleDialogFragment.java b/src/com/android/settings/localepicker/LocaleDialogFragment.java
index 2dc09bd..ad9e10f 100644
--- a/src/com/android/settings/localepicker/LocaleDialogFragment.java
+++ b/src/com/android/settings/localepicker/LocaleDialogFragment.java
@@ -21,8 +21,8 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.os.Bundle;
-import android.os.ResultReceiver;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -35,7 +35,6 @@
import com.android.internal.app.LocaleStore;
import com.android.settings.R;
-import com.android.settings.RestrictedSettingsFragment;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -46,49 +45,19 @@
public class LocaleDialogFragment extends InstrumentedDialogFragment {
private static final String TAG = LocaleDialogFragment.class.getSimpleName();
- static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 0;
- static final int DIALOG_NOT_AVAILABLE_LOCALE = 1;
+ static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 1;
+ static final int DIALOG_NOT_AVAILABLE_LOCALE = 2;
static final String ARG_DIALOG_TYPE = "arg_dialog_type";
static final String ARG_TARGET_LOCALE = "arg_target_locale";
- static final String ARG_RESULT_RECEIVER = "arg_result_receiver";
+ static final String ARG_SHOW_DIALOG = "arg_show_dialog";
+
+ private boolean mShouldKeepDialog;
public static LocaleDialogFragment newInstance() {
return new LocaleDialogFragment();
}
- /**
- * Show dialog
- */
- public void show(
- @NonNull RestrictedSettingsFragment fragment,
- int dialogType,
- LocaleStore.LocaleInfo localeInfo) {
- if (!isAdded()) {
- return;
- }
- show(fragment, dialogType, localeInfo, null);
- }
-
- /**
- * Show dialog
- */
- public void show(
- @NonNull RestrictedSettingsFragment fragment,
- int dialogType,
- LocaleStore.LocaleInfo localeInfo,
- ResultReceiver resultReceiver) {
- FragmentManager manager = fragment.getChildFragmentManager();
- Bundle args = new Bundle();
- args.putInt(ARG_DIALOG_TYPE, dialogType);
- args.putSerializable(ARG_TARGET_LOCALE, localeInfo);
- args.putParcelable(ARG_RESULT_RECEIVER, resultReceiver);
-
- LocaleDialogFragment localeDialogFragment = new LocaleDialogFragment();
- localeDialogFragment.setArguments(args);
- localeDialogFragment.show(manager, TAG);
- }
-
@Override
public int getMetricsCategory() {
int dialogType = getArguments().getInt(ARG_DIALOG_TYPE);
@@ -103,8 +72,28 @@
}
@Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(ARG_SHOW_DIALOG, mShouldKeepDialog);
+ }
+
+ @Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
- LocaleDialogController controller = new LocaleDialogController(this);
+ if (savedInstanceState != null) {
+ Bundle arguments = getArguments();
+ int type = arguments.getInt(ARG_DIALOG_TYPE);
+ mShouldKeepDialog = savedInstanceState.getBoolean(ARG_SHOW_DIALOG, false);
+ // Keep the dialog if user rotates the device, otherwise close the confirm system
+ // default dialog only when user changes the locale.
+ if (type == DIALOG_CONFIRM_SYSTEM_DEFAULT && !mShouldKeepDialog) {
+ dismiss();
+ }
+ }
+
+ mShouldKeepDialog = true;
+ LocaleListEditor parentFragment = (LocaleListEditor) getParentFragment();
+ LocaleDialogController controller = getLocaleDialogController(getContext(), this,
+ parentFragment);
LocaleDialogController.DialogContent dialogContent = controller.getDialogContent();
ViewGroup viewGroup = (ViewGroup) LayoutInflater.from(getContext()).inflate(
R.layout.locale_dialog, null);
@@ -140,47 +129,57 @@
textView.setText(content);
}
- static class LocaleDialogController implements DialogInterface.OnClickListener {
+ @VisibleForTesting
+ LocaleDialogController getLocaleDialogController(Context context,
+ LocaleDialogFragment dialogFragment, LocaleListEditor parentFragment) {
+ return new LocaleDialogController(context, dialogFragment, parentFragment);
+ }
+
+ class LocaleDialogController implements DialogInterface.OnClickListener {
private final Context mContext;
private final int mDialogType;
private final LocaleStore.LocaleInfo mLocaleInfo;
- private final ResultReceiver mResultReceiver;
private final MetricsFeatureProvider mMetricsFeatureProvider;
+ private LocaleListEditor mParent;
+
LocaleDialogController(
- @NonNull Context context, @NonNull LocaleDialogFragment dialogFragment) {
+ @NonNull Context context, @NonNull LocaleDialogFragment dialogFragment,
+ LocaleListEditor parentFragment) {
mContext = context;
Bundle arguments = dialogFragment.getArguments();
mDialogType = arguments.getInt(ARG_DIALOG_TYPE);
- mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(
- ARG_TARGET_LOCALE);
- mResultReceiver = (ResultReceiver) arguments.getParcelable(ARG_RESULT_RECEIVER);
+ mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(ARG_TARGET_LOCALE);
mMetricsFeatureProvider = FeatureFactory.getFactory(
mContext).getMetricsFeatureProvider();
+ mParent = parentFragment;
}
- LocaleDialogController(@NonNull LocaleDialogFragment dialogFragment) {
- this(dialogFragment.getContext(), dialogFragment);
+ LocaleDialogController(@NonNull LocaleDialogFragment dialogFragment,
+ LocaleListEditor parent) {
+ this(dialogFragment.getContext(), dialogFragment, parent);
}
@Override
public void onClick(DialogInterface dialog, int which) {
- if (mResultReceiver != null && mDialogType == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+ if (mDialogType == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+ int result = Activity.RESULT_CANCELED;
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ result = Activity.RESULT_OK;
+ }
+ Intent intent = new Intent();
Bundle bundle = new Bundle();
bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
- if (which == DialogInterface.BUTTON_POSITIVE) {
- mResultReceiver.send(Activity.RESULT_OK, bundle);
- } else if (which == DialogInterface.BUTTON_NEGATIVE) {
- mResultReceiver.send(Activity.RESULT_CANCELED, bundle);
- }
+ intent.putExtras(bundle);
+ mParent.onActivityResult(DIALOG_CONFIRM_SYSTEM_DEFAULT, result, intent);
mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE);
}
+ mShouldKeepDialog = false;
}
@VisibleForTesting
DialogContent getDialogContent() {
- DialogContent
- dialogContent = new DialogContent();
+ DialogContent dialogContent = new DialogContent();
switch (mDialogType) {
case DIALOG_CONFIRM_SYSTEM_DEFAULT:
dialogContent.mTitle = String.format(mContext.getString(
diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
index 2223db0..edd3026 100644
--- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
+++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
@@ -16,14 +16,11 @@
package com.android.settings.localepicker;
-import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Bundle;
-import android.os.Handler;
import android.os.LocaleList;
-import android.os.Looper;
-import android.os.ResultReceiver;
+import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
@@ -52,15 +49,20 @@
private static final String TAG = "LocaleDragAndDropAdapter";
private static final String CFGKEY_SELECTED_LOCALES = "selectedLocales";
+ private static final String CFGKEY_DRAG_LOCALE = "dragLocales";
+ private static final String CFGKEY_DRAG_LOCALES_TO_POSITION = "dragLocales_end";
+
private final Context mContext;
+ private final ItemTouchHelper mItemTouchHelper;
+
private List<LocaleStore.LocaleInfo> mFeedItemList;
private List<LocaleStore.LocaleInfo> mCacheItemList;
- private final ItemTouchHelper mItemTouchHelper;
private RecyclerView mParentView = null;
private LocaleListEditor mParent;
private boolean mRemoveMode = false;
private boolean mDragEnabled = true;
private NumberFormat mNumberFormatter = NumberFormat.getNumberInstance();
+ private LocaleStore.LocaleInfo mDragLocale;
class CustomViewHolder extends RecyclerView.ViewHolder implements View.OnTouchListener {
private final LocaleDragCell mLocaleDragCell;
@@ -87,8 +89,7 @@
}
}
- LocaleDragAndDropAdapter(LocaleListEditor parent,
- List<LocaleStore.LocaleInfo> feedItemList) {
+ LocaleDragAndDropAdapter(LocaleListEditor parent, List<LocaleStore.LocaleInfo> feedItemList) {
mFeedItemList = feedItemList;
mParent = parent;
mCacheItemList = new ArrayList<>(feedItemList);
@@ -202,6 +203,7 @@
final LocaleStore.LocaleInfo saved = mFeedItemList.get(fromPosition);
mFeedItemList.remove(fromPosition);
mFeedItemList.add(toPosition, saved);
+ mDragLocale = saved;
} else {
// TODO: It looks like sometimes the RecycleView tries to swap item -1
// I did not see it in a while, but if it happens, investigate and file a bug.
@@ -317,43 +319,20 @@
});
}
- public void doTheUpdateWithMovingLocaleItem() {
- LocaleStore.LocaleInfo localeInfo = mFeedItemList.get(0);
- final LocaleDialogFragment fragment = LocaleDialogFragment.newInstance();
- if (!localeInfo.getLocale().equals(LocalePicker.getLocales().get(0))) {
- fragment.show(mParent,
- LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT,
- localeInfo,
- new ResultReceiver(new Handler(Looper.getMainLooper())) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- super.onReceiveResult(resultCode, resultData);
- int type = resultData.getInt(LocaleDialogFragment.ARG_DIALOG_TYPE);
- if (type == LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT) {
- if (resultCode == Activity.RESULT_OK) {
- doTheUpdate();
- if (!localeInfo.isTranslated()) {
- fragment.show(mParent,
- LocaleDialogFragment
- .DIALOG_NOT_AVAILABLE_LOCALE,
- localeInfo);
- }
- } else {
- if (!localeInfo.getLocale()
- .equals(mCacheItemList.get(0).getLocale())) {
- mFeedItemList = new ArrayList<>(mCacheItemList);
- notifyDataSetChanged();
- }
- }
- mCacheItemList = new ArrayList<>(mFeedItemList);
- }
- }
- });
- } else {
- doTheUpdate();
+ public void notifyListChanged(LocaleStore.LocaleInfo localeInfo) {
+ if (!localeInfo.getLocale().equals(mCacheItemList.get(0).getLocale())) {
+ mFeedItemList = new ArrayList<>(mCacheItemList);
+ notifyDataSetChanged();
}
}
+ public void setCacheItemList() {
+ mCacheItemList = new ArrayList<>(mFeedItemList);
+ }
+
+ public List<LocaleStore.LocaleInfo> getFeedItemList() {
+ return mFeedItemList;
+ }
private void setDragEnabled(boolean enabled) {
mDragEnabled = enabled;
}
@@ -373,6 +352,8 @@
}
}
outInstanceState.putStringArrayList(CFGKEY_SELECTED_LOCALES, selectedLocales);
+ // Save the dragged locale before rotation
+ outInstanceState.putSerializable(CFGKEY_DRAG_LOCALE, mDragLocale);
}
}
@@ -381,18 +362,30 @@
* (for instance when the device is rotated)
*
* @param savedInstanceState Bundle with the data saved by {@link #saveState(Bundle)}
+ * @param isDialogShowing A flag indicating whether the dialog is showing or not.
*/
- public void restoreState(Bundle savedInstanceState) {
- if (savedInstanceState != null && mRemoveMode) {
- final ArrayList<String> selectedLocales =
- savedInstanceState.getStringArrayList(CFGKEY_SELECTED_LOCALES);
- if (selectedLocales == null || selectedLocales.isEmpty()) {
- return;
+ public void restoreState(Bundle savedInstanceState, boolean isDialogShowing) {
+ if (savedInstanceState != null) {
+ if (mRemoveMode) {
+ final ArrayList<String> selectedLocales =
+ savedInstanceState.getStringArrayList(CFGKEY_SELECTED_LOCALES);
+ if (selectedLocales == null || selectedLocales.isEmpty()) {
+ return;
+ }
+ for (LocaleStore.LocaleInfo li : mFeedItemList) {
+ li.setChecked(selectedLocales.contains(li.getId()));
+ }
+ notifyItemRangeChanged(0, mFeedItemList.size());
+ } else if (isDialogShowing) {
+ // After rotation, the dragged position will be restored to original. Restore the
+ // drag locale's original position to the top.
+ mDragLocale = (LocaleStore.LocaleInfo) savedInstanceState.getSerializable(
+ CFGKEY_DRAG_LOCALE);
+ mFeedItemList.removeIf(
+ localeInfo -> TextUtils.equals(localeInfo.getId(), mDragLocale.getId()));
+ mFeedItemList.add(0, mDragLocale);
+ notifyItemRangeChanged(0, mFeedItemList.size());
}
- for (LocaleStore.LocaleInfo li : mFeedItemList) {
- li.setChecked(selectedLocales.contains(li.getId()));
- }
- notifyItemRangeChanged(0, mFeedItemList.size());
}
}
}
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index 6317f24..7ec08f7 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -18,6 +18,8 @@
import static android.os.UserManager.DISALLOW_CONFIG_LOCALE;
+import static com.android.settings.localepicker.LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT;
+
import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
@@ -32,12 +34,14 @@
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.FragmentManager;
import androidx.preference.PreferenceScreen;
import androidx.recyclerview.widget.RecyclerView;
@@ -60,7 +64,7 @@
* Drag-and-drop editor for the user-ordered locale lists.
*/
@SearchIndexable
-public class LocaleListEditor extends RestrictedSettingsFragment {
+public class LocaleListEditor extends RestrictedSettingsFragment implements View.OnTouchListener {
protected static final String INTENT_LOCALE_KEY = "localeInfo";
private static final String CFGKEY_REMOVE_MODE = "localeRemoveMode";
@@ -70,6 +74,8 @@
private static final String INDEX_KEY_ADD_LANGUAGE = "add_language";
private static final String KEY_LANGUAGES_PICKER = "languages_picker";
+ private static final String TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT = "dialog_confirm_system_default";
+ private static final String TAG_DIALOG_NOT_AVAILABLE = "dialog_not_available_locale";
private LocaleDragAndDropAdapter mAdapter;
private Menu mMenu;
@@ -80,6 +86,7 @@
private LayoutPreference mLocalePickerPreference;
private LocaleHelperPreferenceController mLocaleHelperPreferenceController;
+ private FragmentManager mFragmentManager;
public LocaleListEditor() {
super(DISALLOW_CONFIG_LOCALE);
@@ -106,6 +113,7 @@
LocaleStore.fillCache(this.getContext());
final List<LocaleStore.LocaleInfo> feedsList = getUserLocaleList();
mAdapter = new LocaleDragAndDropAdapter(this, feedsList);
+ mFragmentManager = getChildFragmentManager();
}
@Override
@@ -141,7 +149,15 @@
mShowingRemoveDialog = savedInstanceState.getBoolean(CFGKEY_REMOVE_DIALOG, false);
}
setRemoveMode(mRemoveMode);
- mAdapter.restoreState(savedInstanceState);
+
+ final LocaleDialogFragment dialogFragment =
+ (LocaleDialogFragment) mFragmentManager.findFragmentByTag(
+ TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT);
+ boolean isDialogShowing = false;
+ if (dialogFragment != null && dialogFragment.isAdded()) {
+ isDialogShowing = true;
+ }
+ mAdapter.restoreState(savedInstanceState, isDialogShowing);
if (mShowingRemoveDialog) {
showRemoveLocaleWarningDialog();
@@ -178,17 +194,32 @@
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ LocaleStore.LocaleInfo localeInfo;
if (requestCode == REQUEST_LOCALE_PICKER && resultCode == Activity.RESULT_OK
&& data != null) {
- final LocaleStore.LocaleInfo localeInfo =
- (LocaleStore.LocaleInfo) data.getSerializableExtra(
- INTENT_LOCALE_KEY);
-
+ localeInfo = (LocaleStore.LocaleInfo) data.getSerializableExtra(INTENT_LOCALE_KEY);
String preferencesTags = Settings.System.getString(
getContext().getContentResolver(), Settings.System.LOCALE_PREFERENCES);
mAdapter.addLocale(mayAppendUnicodeTags(localeInfo, preferencesTags));
updateVisibilityOfRemoveMenu();
+ } else if (requestCode == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
+ localeInfo = mAdapter.getFeedItemList().get(0);
+ if (resultCode == Activity.RESULT_OK) {
+ mAdapter.doTheUpdate();
+ if (!localeInfo.isTranslated()) {
+ Bundle args = new Bundle();
+ args.putInt(LocaleDialogFragment.ARG_DIALOG_TYPE,
+ LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE);
+ args.putSerializable(LocaleDialogFragment.ARG_TARGET_LOCALE, localeInfo);
+ LocaleDialogFragment localeDialogFragment = LocaleDialogFragment.newInstance();
+ localeDialogFragment.setArguments(args);
+ localeDialogFragment.show(mFragmentManager, TAG_DIALOG_NOT_AVAILABLE);
+ }
+ } else {
+ mAdapter.notifyListChanged(localeInfo);
+ }
+ mAdapter.setCacheItemList();
}
super.onActivityResult(requestCode, resultCode, data);
}
@@ -332,6 +363,7 @@
list.setNestedScrollingEnabled(false);
mAdapter.setRecyclerView(list);
list.setAdapter(mAdapter);
+ list.setOnTouchListener(this);
mAddLanguage = layout.findViewById(R.id.add_language);
mAddLanguage.setOnClickListener(new View.OnClickListener() {
@@ -348,6 +380,26 @@
});
}
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ if (event.getAction() == MotionEvent.ACTION_UP
+ || event.getAction() == MotionEvent.ACTION_CANCEL) {
+ LocaleStore.LocaleInfo localeInfo = mAdapter.getFeedItemList().get(0);
+ if (!localeInfo.getLocale().equals(LocalePicker.getLocales().get(0))) {
+ final LocaleDialogFragment localeDialogFragment =
+ LocaleDialogFragment.newInstance();
+ Bundle args = new Bundle();
+ args.putInt(LocaleDialogFragment.ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
+ args.putSerializable(LocaleDialogFragment.ARG_TARGET_LOCALE, localeInfo);
+ localeDialogFragment.setArguments(args);
+ localeDialogFragment.show(mFragmentManager, TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT);
+ } else {
+ mAdapter.doTheUpdate();
+ }
+ }
+ return false;
+ }
+
// Hide the "Remove" menu if there is only one locale in the list, show it otherwise
// This is called when the menu is first created, and then one add / remove locale
private void updateVisibilityOfRemoveMenu() {
diff --git a/src/com/android/settings/localepicker/LocaleRecyclerView.java b/src/com/android/settings/localepicker/LocaleRecyclerView.java
index 5d469bf..4a5f28b 100644
--- a/src/com/android/settings/localepicker/LocaleRecyclerView.java
+++ b/src/com/android/settings/localepicker/LocaleRecyclerView.java
@@ -34,15 +34,4 @@
public LocaleRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
-
- @Override
- public boolean onTouchEvent(MotionEvent e) {
- if (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_CANCEL) {
- LocaleDragAndDropAdapter adapter = (LocaleDragAndDropAdapter) this.getAdapter();
- if (adapter != null) {
- adapter.doTheUpdateWithMovingLocaleItem();
- }
- }
- return super.onTouchEvent(e);
- }
}
diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.java b/src/com/android/settings/network/MobileNetworkSummaryController.java
index 99a2731..1474836 100644
--- a/src/com/android/settings/network/MobileNetworkSummaryController.java
+++ b/src/com/android/settings/network/MobileNetworkSummaryController.java
@@ -24,7 +24,6 @@
import android.os.UserManager;
import android.telephony.SubscriptionManager;
import android.telephony.euicc.EuiccManager;
-import android.util.Log;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
@@ -135,6 +134,7 @@
return mContext.getString(R.string.mobile_network_tap_to_activate, displayName);
} else {
return mSubInfoEntityList.stream()
+ .sorted((e1, e2) -> Integer.compare(e1.simSlotIndex, e2.simSlotIndex))
.map(SubscriptionInfoEntity::getUniqueDisplayName)
.collect(Collectors.joining(", "));
}
diff --git a/src/com/android/settings/network/tether/TetherSettings.java b/src/com/android/settings/network/tether/TetherSettings.java
index ba19d1c..9fa8730 100644
--- a/src/com/android/settings/network/tether/TetherSettings.java
+++ b/src/com/android/settings/network/tether/TetherSettings.java
@@ -171,6 +171,8 @@
return;
}
+ setupTetherPreference();
+
final Activity activity = getActivity();
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (adapter != null) {
@@ -184,7 +186,6 @@
new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED));
}
- setupTetherPreference();
setTopIntroPreferenceTitle();
mDataSaverBackend.addListener(this);
@@ -605,6 +606,7 @@
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (mBluetoothPan.get() == null) {
mBluetoothPan.set((BluetoothPan) proxy);
+ updateBluetoothState();
}
}
diff --git a/src/com/android/settings/password/BiometricFragment.java b/src/com/android/settings/password/BiometricFragment.java
index d364c71..4ad04a1 100644
--- a/src/com/android/settings/password/BiometricFragment.java
+++ b/src/com/android/settings/password/BiometricFragment.java
@@ -141,6 +141,7 @@
.setDisallowBiometricsIfPolicyExists(
promptInfo.isDisallowBiometricsIfPolicyExists())
.setReceiveSystemEvents(true)
+ .setAllowBackgroundAuthentication(true)
.build();
}
diff --git a/src/com/android/settings/privacy/PrivacyDashboardFragment.java b/src/com/android/settings/privacy/PrivacyDashboardFragment.java
index 19683b8..4d76277 100644
--- a/src/com/android/settings/privacy/PrivacyDashboardFragment.java
+++ b/src/com/android/settings/privacy/PrivacyDashboardFragment.java
@@ -59,8 +59,10 @@
SafetyCenterUtils.getEnterpriseOverrideStringForPrivacyEntries();
for (int i = 0; i < privacyOverrideStrings.size(); i++) {
EnterpriseOverrideString overrideString = privacyOverrideStrings.get(i);
- replaceEnterpriseStringTitle(overrideString.getPreferenceKey(),
- overrideString.getOverrideKey(), overrideString.getResource());
+ replaceEnterpriseStringTitle(
+ overrideString.getPreferenceKey(),
+ overrideString.getOverrideKey(),
+ overrideString.getResource());
}
}
@@ -93,7 +95,9 @@
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) {
- if (SafetyCenterManagerWrapper.get().isEnabled(context)) {
+ // NOTE: This check likely should be moved to the super method. This is done
+ // here to avoid potentially undesired side effects for existing implementors.
+ if (!isPageSearchEnabled(context)) {
return null;
}
return super.getXmlResourcesToIndex(context, enabled);
@@ -120,5 +124,10 @@
keys.add(KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS);
return keys;
}
+
+ @Override
+ protected boolean isPageSearchEnabled(Context context) {
+ return !SafetyCenterManagerWrapper.get().isEnabled(context);
+ }
};
}
diff --git a/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragment.java b/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragment.java
index 3eb6102..69ec385 100644
--- a/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragment.java
+++ b/src/com/android/settings/safetycenter/MoreSecurityPrivacyFragment.java
@@ -77,21 +77,23 @@
SafetyCenterUtils.getEnterpriseOverrideStringForPrivacyEntries();
for (int i = 0; i < privacyOverrideStrings.size(); i++) {
EnterpriseOverrideString overrideString = privacyOverrideStrings.get(i);
- replaceEnterpriseStringTitle(overrideString.getPreferenceKey(),
- overrideString.getOverrideKey(), overrideString.getResource());
+ replaceEnterpriseStringTitle(
+ overrideString.getPreferenceKey(),
+ overrideString.getOverrideKey(),
+ overrideString.getResource());
}
List<EnterpriseOverrideString> securityOverrideStrings =
SafetyCenterUtils.getEnterpriseOverrideStringForSecurityEntries();
for (int i = 0; i < securityOverrideStrings.size(); i++) {
EnterpriseOverrideString overrideString = securityOverrideStrings.get(i);
- replaceEnterpriseStringTitle(overrideString.getPreferenceKey(),
- overrideString.getOverrideKey(), overrideString.getResource());
+ replaceEnterpriseStringTitle(
+ overrideString.getPreferenceKey(),
+ overrideString.getOverrideKey(),
+ overrideString.getResource());
}
}
- /**
- * see confirmPatternThenDisableAndClear
- */
+ /** see confirmPatternThenDisableAndClear */
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (use(TrustAgentListPreferenceController.class)
@@ -117,10 +119,8 @@
controllers.addAll(
SafetyCenterUtils.getControllersForAdvancedSecurity(context, lifecycle, host));
return controllers;
-
}
-
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.more_security_privacy_settings) {
/**
@@ -130,7 +130,9 @@
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) {
- if (!SafetyCenterManagerWrapper.get().isEnabled(context)) {
+ // NOTE: This check likely should be moved to the super method. This is done
+ // here to avoid potentially undesired side effects for existing implementors.
+ if (!isPageSearchEnabled(context)) {
return null;
}
return super.getXmlResourcesToIndex(context, enabled);
@@ -157,5 +159,10 @@
keys.add(KEY_NOTIFICATION_WORK_PROFILE_NOTIFICATIONS);
return keys;
}
+
+ @Override
+ protected boolean isPageSearchEnabled(Context context) {
+ return SafetyCenterManagerWrapper.get().isEnabled(context);
+ }
};
}
diff --git a/src/com/android/settings/security/SecurityAdvancedSettings.java b/src/com/android/settings/security/SecurityAdvancedSettings.java
index b2b2782..61f0975 100644
--- a/src/com/android/settings/security/SecurityAdvancedSettings.java
+++ b/src/com/android/settings/security/SecurityAdvancedSettings.java
@@ -58,8 +58,10 @@
SafetyCenterUtils.getEnterpriseOverrideStringForSecurityEntries();
for (int i = 0; i < securityOverrideStrings.size(); i++) {
EnterpriseOverrideString overrideString = securityOverrideStrings.get(i);
- replaceEnterpriseStringTitle(overrideString.getPreferenceKey(),
- overrideString.getOverrideKey(), overrideString.getResource());
+ replaceEnterpriseStringTitle(
+ overrideString.getPreferenceKey(),
+ overrideString.getOverrideKey(),
+ overrideString.getResource());
}
}
@@ -77,8 +79,7 @@
return CategoryKey.CATEGORY_SECURITY_ADVANCED_SETTINGS;
} else {
final SecuritySettingsFeatureProvider securitySettingsFeatureProvider =
- FeatureFactory.getFactory(context)
- .getSecuritySettingsFeatureProvider();
+ FeatureFactory.getFactory(context).getSecuritySettingsFeatureProvider();
if (securitySettingsFeatureProvider.hasAlternativeSecuritySettingsFragment()) {
return securitySettingsFeatureProvider.getAlternativeAdvancedSettingsCategoryKey();
@@ -103,9 +104,7 @@
return buildPreferenceControllers(context, getSettingsLifecycle(), this /* host*/);
}
- /**
- * see confirmPatternThenDisableAndClear
- */
+ /** see confirmPatternThenDisableAndClear */
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (use(TrustAgentListPreferenceController.class)
@@ -119,14 +118,12 @@
super.onActivityResult(requestCode, resultCode, data);
}
- private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
- Lifecycle lifecycle, DashboardFragment host) {
+ private static List<AbstractPreferenceController> buildPreferenceControllers(
+ Context context, Lifecycle lifecycle, DashboardFragment host) {
return SafetyCenterUtils.getControllersForAdvancedSecurity(context, lifecycle, host);
}
- /**
- * For Search. Please keep it in sync when updating "createPreferenceHierarchy()"
- */
+ /** For Search. Please keep it in sync when updating "createPreferenceHierarchy()" */
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.security_advanced_settings) {
/**
@@ -134,19 +131,26 @@
* page, and we don't want to index these entries.
*/
@Override
- public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
- boolean enabled) {
- if (SafetyCenterManagerWrapper.get().isEnabled(context)) {
+ public List<SearchIndexableResource> getXmlResourcesToIndex(
+ Context context, boolean enabled) {
+ // NOTE: This check likely should be moved to the super method. This is done
+ // here to avoid potentially undesired side effects for existing implementors.
+ if (!isPageSearchEnabled(context)) {
return null;
}
return super.getXmlResourcesToIndex(context, enabled);
}
@Override
- public List<AbstractPreferenceController> createPreferenceControllers(Context
- context) {
- return buildPreferenceControllers(context, null /* lifecycle */,
- null /* host*/);
+ public List<AbstractPreferenceController> createPreferenceControllers(
+ Context context) {
+ return buildPreferenceControllers(
+ context, null /* lifecycle */, null /* host*/);
+ }
+
+ @Override
+ protected boolean isPageSearchEnabled(Context context) {
+ return !SafetyCenterManagerWrapper.get().isEnabled(context);
}
};
}
diff --git a/src/com/android/settings/slices/SlicePreferenceController.java b/src/com/android/settings/slices/SlicePreferenceController.java
index df28304..eb10bd4 100644
--- a/src/com/android/settings/slices/SlicePreferenceController.java
+++ b/src/com/android/settings/slices/SlicePreferenceController.java
@@ -44,6 +44,7 @@
LiveData<Slice> mLiveData;
@VisibleForTesting
SlicePreference mSlicePreference;
+ private boolean mIsObservering = false;
private Uri mUri;
public SlicePreferenceController(Context context, String preferenceKey) {
@@ -68,25 +69,31 @@
});
//TODO(b/120803703): figure out why we need to remove observer first
- mLiveData.removeObserver(this);
+ removeLiveDataObserver();
}
@Override
public void onStart() {
- if (mLiveData != null) {
+ if (mLiveData != null && !mIsObservering) {
+ mIsObservering = true;
mLiveData.observeForever(this);
}
}
@Override
public void onStop() {
- if (mLiveData != null) {
- mLiveData.removeObserver(this);
- }
+ removeLiveDataObserver();
}
@Override
public void onChanged(Slice slice) {
mSlicePreference.onSliceUpdated(slice);
}
+
+ private void removeLiveDataObserver() {
+ if (mLiveData != null && mIsObservering && mLiveData.hasActiveObservers()) {
+ mIsObservering = false;
+ mLiveData.removeObserver(this);
+ }
+ }
}
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index d904ed0..28e02ec 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -28,7 +28,6 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.SharedPreferences;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -83,6 +82,7 @@
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.search.SearchIndexableRaw;
+import com.android.settingslib.users.CreateUserDialogController;
import com.android.settingslib.users.EditUserInfoController;
import com.android.settingslib.users.GrantAdminDialogController;
import com.android.settingslib.users.UserCreatingDialog;
@@ -119,6 +119,7 @@
/** UserId of the user being removed */
private static final String SAVE_REMOVING_USER = "removing_user";
+ private static final String SAVE_CREATE_USER = "create_user";
private static final String KEY_USER_LIST = "user_list";
private static final String KEY_USER_ME = "user_me";
@@ -171,9 +172,6 @@
static final int RESULT_GUEST_REMOVED = 100;
- private static final String KEY_ADD_USER_LONG_MESSAGE_DISPLAYED =
- "key_add_user_long_message_displayed";
-
private static final String KEY_TITLE = "title";
private static final String KEY_SUMMARY = "summary";
@@ -222,6 +220,8 @@
new GrantAdminDialogController();
private EditUserInfoController mEditUserInfoController =
new EditUserInfoController(Utils.FILE_PROVIDER_AUTHORITY);
+ private CreateUserDialogController mCreateUserDialogController =
+ new CreateUserDialogController(Utils.FILE_PROVIDER_AUTHORITY);
private AddUserWhenLockedPreferenceController mAddUserWhenLockedPreferenceController;
private GuestTelephonyPreferenceController mGuestTelephonyPreferenceController;
private RemoveGuestOnExitPreferenceController mRemoveGuestOnExitPreferenceController;
@@ -233,7 +233,7 @@
private CharSequence mPendingUserName;
private Drawable mPendingUserIcon;
- private boolean mGrantAdmin;
+ private boolean mPendingUserIsAdmin;
// A place to cache the generated default avatar
private Drawable mDefaultIconDrawable;
@@ -348,7 +348,11 @@
if (icicle.containsKey(SAVE_REMOVING_USER)) {
mRemovingUserId = icicle.getInt(SAVE_REMOVING_USER);
}
- mEditUserInfoController.onRestoreInstanceState(icicle);
+ if (icicle.containsKey(SAVE_CREATE_USER)) {
+ mCreateUserDialogController.onRestoreInstanceState(icicle);
+ } else {
+ mEditUserInfoController.onRestoreInstanceState(icicle);
+ }
}
mUserCaps = UserCapabilities.create(activity);
@@ -440,7 +444,12 @@
@Override
public void onSaveInstanceState(Bundle outState) {
- mEditUserInfoController.onSaveInstanceState(outState);
+ if (mCreateUserDialogController.isActive()) {
+ outState.putBoolean(SAVE_CREATE_USER, mCreateUserDialogController.isActive());
+ mCreateUserDialogController.onSaveInstanceState(outState);
+ } else {
+ mEditUserInfoController.onSaveInstanceState(outState);
+ }
outState.putInt(SAVE_REMOVING_USER, mRemovingUserId);
super.onSaveInstanceState(outState);
}
@@ -448,6 +457,7 @@
@Override
public void startActivityForResult(Intent intent, int requestCode) {
mEditUserInfoController.startingActivityForResult();
+ mCreateUserDialogController.startingActivityForResult();
super.startActivityForResult(intent, requestCode);
}
@@ -562,6 +572,7 @@
&& resultCode == RESULT_GUEST_REMOVED) {
scheduleGuestCreation();
} else {
+ mCreateUserDialogController.onActivityResult(requestCode, resultCode, data);
mEditUserInfoController.onActivityResult(requestCode, resultCode, data);
}
}
@@ -704,37 +715,12 @@
.setPositiveButton(android.R.string.ok, null)
.create();
case DIALOG_ADD_USER: {
- final SharedPreferences preferences = getActivity().getPreferences(
- Context.MODE_PRIVATE);
- final boolean longMessageDisplayed = preferences.getBoolean(
- KEY_ADD_USER_LONG_MESSAGE_DISPLAYED, false);
- final int messageResId = longMessageDisplayed
- ? com.android.settingslib.R.string.user_add_user_message_short
- : com.android.settingslib.R.string.user_add_user_message_long;
- Dialog dlg = new AlertDialog.Builder(context)
- .setTitle(com.android.settingslib.R.string.user_add_user_title)
- .setMessage(messageResId)
- .setPositiveButton(android.R.string.ok,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- if (!longMessageDisplayed) {
- preferences.edit().putBoolean(
- KEY_ADD_USER_LONG_MESSAGE_DISPLAYED,
- true).apply();
- }
- if (UserManager.isMultipleAdminEnabled()) {
- showDialog(DIALOG_GRANT_ADMIN);
- } else {
- showDialog(DIALOG_USER_PROFILE_EDITOR_ADD_USER);
- }
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .create();
- return dlg;
- }
- case DIALOG_GRANT_ADMIN: {
- return buildGrantAdminDialog();
+ synchronized (mUserLock) {
+ mPendingUserName = getString(
+ com.android.settingslib.R.string.user_new_user_name);
+ mPendingUserIcon = null;
+ }
+ return buildAddUserDialog(USER_TYPE_USER);
}
case DIALOG_CHOOSE_USER_TYPE: {
List<HashMap<String, String>> data = new ArrayList<HashMap<String, String>>();
@@ -919,17 +905,14 @@
private Dialog buildAddUserDialog(int userType) {
Dialog d;
synchronized (mUserLock) {
- d = mEditUserInfoController.createDialog(
+ d = mCreateUserDialogController.createDialog(
getActivity(),
this::startActivityForResult,
- null,
- mPendingUserName.toString(),
- getString(userType == USER_TYPE_USER
- ? com.android.settingslib.R.string.user_info_settings_title
- : com.android.settingslib.R.string.profile_info_settings_title),
- (userName, userIcon) -> {
+ UserManager.isMultipleAdminEnabled(),
+ (userName, userIcon, isAdmin) -> {
mPendingUserIcon = userIcon;
mPendingUserName = userName;
+ mPendingUserIsAdmin = isAdmin;
addUserNow(userType);
},
() -> {
@@ -943,26 +926,6 @@
return d;
}
- private Dialog buildGrantAdminDialog() {
- return mGrantAdminDialogController.createDialog(
- getActivity(),
- (grantAdmin) -> {
- mGrantAdmin = grantAdmin;
- if (mGrantAdmin) {
- mMetricsFeatureProvider.action(getActivity(),
- SettingsEnums.ACTION_GRANT_ADMIN_FROM_SETTINGS_CREATION_DIALOG);
- } else {
- mMetricsFeatureProvider.action(getActivity(),
- SettingsEnums.ACTION_NOT_GRANT_ADMIN_FROM_SETTINGS_CREATION_DIALOG);
- }
- showDialog(DIALOG_USER_PROFILE_EDITOR_ADD_USER);
- },
- () -> {
- mGrantAdmin = false;
- }
- );
- }
-
@Override
public int getDialogMetricsCategory(int dialogId) {
switch (dialogId) {
@@ -1065,7 +1028,7 @@
userName,
mUserManager.USER_TYPE_FULL_SECONDARY,
0);
- if (mGrantAdmin) {
+ if (mPendingUserIsAdmin) {
mUserManager.setUserAdmin(user.id);
}
} else {
@@ -1665,6 +1628,9 @@
synchronized (mUserLock) {
mRemovingUserId = -1;
updateUserList();
+ if (mCreateUserDialogController.isActive()) {
+ mCreateUserDialogController.clear();
+ }
}
}
diff --git a/tests/robotests/src/com/android/settings/AllInOneTetherSettingsTest.java b/tests/robotests/src/com/android/settings/AllInOneTetherSettingsTest.java
index 9eb2cee..f4a20fe 100644
--- a/tests/robotests/src/com/android/settings/AllInOneTetherSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/AllInOneTetherSettingsTest.java
@@ -45,6 +45,8 @@
import androidx.preference.PreferenceScreen;
import com.android.settings.core.FeatureFlags;
+import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.wifi.repository.WifiHotspotRepository;
import com.android.settings.wifi.tether.WifiTetherAutoOffPreferenceController;
import com.android.settings.wifi.tether.WifiTetherSecurityPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -94,6 +96,8 @@
mContext = spy(RuntimeEnvironment.application);
MockitoAnnotations.initMocks(this);
+ when(FakeFeatureFactory.setupForTest().getWifiFeatureProvider().getWifiHotspotRepository())
+ .thenReturn(mock(WifiHotspotRepository.class));
doReturn(mWifiManager).when(mContext).getSystemService(WifiManager.class);
doReturn(mConnectivityManager)
.when(mContext).getSystemService(Context.CONNECTIVITY_SERVICE);
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
index 5ee7ab3..c68e90b 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilityHearingAidPreferenceControllerTest.java
@@ -24,25 +24,22 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHapClient;
import android.bluetooth.BluetoothHearingAid;
import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
+import android.content.Context;
import android.content.Intent;
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.FragmentActivity;
import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.bluetooth.Utils;
-import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
-import com.android.settings.utils.ActivityControllerWrapper;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
@@ -55,11 +52,12 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.Robolectric;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
@@ -74,6 +72,9 @@
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
public class AccessibilityHearingAidPreferenceControllerTest {
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
private static final String TEST_DEVICE_ADDRESS_2 = "00:A2:A2:A2:A2:A2";
private static final String TEST_DEVICE_NAME = "TEST_HEARING_AID_BT_DEVICE_NAME";
@@ -82,7 +83,8 @@
private BluetoothAdapter mBluetoothAdapter;
private ShadowBluetoothAdapter mShadowBluetoothAdapter;
private BluetoothDevice mBluetoothDevice;
- private Activity mContext;
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+
private Preference mHearingAidPreference;
private AccessibilityHearingAidPreferenceController mPreferenceController;
private ShadowApplication mShadowApplication;
@@ -106,11 +108,7 @@
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
mShadowApplication = ShadowApplication.getInstance();
-
- mContext = spy((Activity) ActivityControllerWrapper.setup(
- Robolectric.buildActivity(Activity.class)).get());
setupEnvironment();
mHearingAidPreference = new Preference(mContext);
@@ -275,65 +273,6 @@
}
@Test
- public void onSupportHearingAidProfile_isAvailable() {
- mShadowBluetoothAdapter.clearSupportedProfiles();
- mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
- mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
- HEARING_AID_PREFERENCE);
- mPreferenceController.setPreference(mHearingAidPreference);
-
- assertThat(mPreferenceController.isAvailable()).isTrue();
- }
-
- @Test
- public void onSupportHapClientProfile_isAvailable() {
- mShadowBluetoothAdapter.clearSupportedProfiles();
- mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HAP_CLIENT);
- mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
- HEARING_AID_PREFERENCE);
- mPreferenceController.setPreference(mHearingAidPreference);
-
- assertThat(mPreferenceController.isAvailable()).isTrue();
- }
-
- @Test
- public void onNotSupportAnyHearingAidRelatedProfile_isNotAvailable() {
- mShadowBluetoothAdapter.clearSupportedProfiles();
- mPreferenceController = new AccessibilityHearingAidPreferenceController(mContext,
- HEARING_AID_PREFERENCE);
- mPreferenceController.setPreference(mHearingAidPreference);
-
- assertThat(mPreferenceController.isAvailable()).isFalse();
- }
-
- @Test
- public void getConnectedHearingAidDevice_doNotReturnSubDevice() {
- when(mHearingAidProfile.getConnectedDevices()).thenReturn(generateHearingAidDeviceList());
- when(mLocalBluetoothManager.getCachedDeviceManager().isSubDevice(mBluetoothDevice))
- .thenReturn(true);
-
- assertThat(mPreferenceController.getConnectedHearingAidDevice()).isNull();
- }
-
- @Test
- @Config(shadows = ShadowAlertDialogCompat.class)
- public void onActiveDeviceChanged_hearingAidProfile_launchHearingAidPairingDialog() {
- final FragmentActivity mActivity = Robolectric.setupActivity(FragmentActivity.class);
- when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true);
- when(mCachedBluetoothDevice.getDeviceMode()).thenReturn(
- HearingAidInfo.DeviceMode.MODE_BINAURAL);
- when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
- HearingAidInfo.DeviceSide.SIDE_LEFT);
- mPreferenceController.setFragmentManager(mActivity.getSupportFragmentManager());
-
- mPreferenceController.onActiveDeviceChanged(mCachedBluetoothDevice,
- BluetoothProfile.HEARING_AID);
-
- final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog();
- assertThat(dialog.isShowing()).isTrue();
- }
-
- @Test
public void onServiceConnected_onHearingAidProfileConnected_updateSummary() {
when(mCachedBluetoothDevice.getDeviceSide()).thenReturn(
HearingAidInfo.DeviceSide.SIDE_LEFT);
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceControllerTest.java
new file mode 100644
index 0000000..d16bc43
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidAudioRoutingPreferenceControllerTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.accessibility;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+/** Tests for {@link HearingAidAudioRoutingPreferenceController}. */
+@RunWith(RobolectricTestRunner.class)
+public class HearingAidAudioRoutingPreferenceControllerTest {
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+
+ private HearingAidAudioRoutingPreferenceController mController;
+
+ @Before
+ public void setUp() {
+ mController = new HearingAidAudioRoutingPreferenceController(mContext, "test_key");
+ }
+
+ @Test
+ public void getAvailabilityStatus_audioRoutingNotSupported_returnUnsupported() {
+ FeatureFlagUtils.setEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, false);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_audioRoutingNotSupported_available() {
+ FeatureFlagUtils.setEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java
new file mode 100644
index 0000000..194b766
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.accessibility;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.bluetooth.Utils;
+import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.HapClientProfile;
+import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/** Tests for {@link HearingAidHelper}. */
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
+public class HearingAidHelperTest {
+ @Rule
+ public final MockitoRule mockito = MockitoJUnit.rule();
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+ private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
+
+ @Mock
+ private LocalBluetoothManager mLocalBluetoothManager;
+ @Mock
+ private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
+ @Mock
+ private CachedBluetoothDeviceManager mCachedDeviceManager;
+ @Mock
+ private CachedBluetoothDevice mCachedBluetoothDevice;
+ @Mock
+ private HearingAidProfile mHearingAidProfile;
+ @Mock
+ private HapClientProfile mHapClientProfile;
+ private ShadowBluetoothAdapter mShadowBluetoothAdapter;
+ private BluetoothAdapter mBluetoothAdapter;
+ private BluetoothDevice mBluetoothDevice;
+ private HearingAidHelper mHelper;
+
+ @Before
+ public void setUp() {
+ ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
+ mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ mShadowBluetoothAdapter = Shadow.extract(mBluetoothAdapter);
+ mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS);
+ when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
+ when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedBluetoothDevice);
+ when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
+ when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
+ when(mLocalBluetoothProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile);
+
+ mHelper = new HearingAidHelper(mContext);
+ }
+
+ @Test
+ public void isHearingAidSupported_supported_returnTrue() {
+ mBluetoothAdapter.enable();
+ mShadowBluetoothAdapter.clearSupportedProfiles();
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+
+ assertThat(mHelper.isHearingAidSupported()).isTrue();
+ }
+
+ @Test
+ public void isHearingAidSupported_bluetoothOff_returnFalse() {
+ mShadowBluetoothAdapter.clearSupportedProfiles();
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+ mBluetoothAdapter.disable();
+
+ assertThat(mHelper.isHearingAidSupported()).isFalse();
+ }
+
+
+ @Test
+ public void isAllHearingAidRelatedProfilesReady_allReady_returnTrue() {
+ when(mHearingAidProfile.isProfileReady()).thenReturn(true);
+ when(mHapClientProfile.isProfileReady()).thenReturn(true);
+
+ assertThat(mHelper.isAllHearingAidRelatedProfilesReady()).isTrue();
+ }
+
+ @Test
+ public void isAllHearingAidRelatedProfilesReady_notFullReady_returnFalse() {
+ when(mHearingAidProfile.isProfileReady()).thenReturn(false);
+ when(mHapClientProfile.isProfileReady()).thenReturn(true);
+
+ assertThat(mHelper.isAllHearingAidRelatedProfilesReady()).isFalse();
+ }
+
+ @Test
+ public void getConnectedHearingAidDeviceList_oneDeviceAdded_getOneDevice() {
+ mBluetoothAdapter.enable();
+ mShadowBluetoothAdapter.clearSupportedProfiles();
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+ when(mHearingAidProfile.getConnectedDevices()).thenReturn(new ArrayList<>(
+ Collections.singletonList(mBluetoothDevice)));
+
+ assertThat(mHelper.getConnectedHearingAidDeviceList().size()).isEqualTo(1);
+ }
+
+ @Test
+ public void getConnectedHearingAidDeviceList_oneSubDeviceAdded_getZeroDevice() {
+ mBluetoothAdapter.enable();
+ mShadowBluetoothAdapter.clearSupportedProfiles();
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+ when(mHearingAidProfile.getConnectedDevices()).thenReturn(new ArrayList<>(
+ Collections.singletonList(mBluetoothDevice)));
+ when(mLocalBluetoothManager.getCachedDeviceManager().isSubDevice(
+ mBluetoothDevice)).thenReturn(true);
+
+ assertThat(mHelper.getConnectedHearingAidDeviceList().size()).isEqualTo(0);
+ }
+
+ @Test
+ public void getConnectedHearingAidDevice_getExpectedCachedBluetoothDevice() {
+ mBluetoothAdapter.enable();
+ mShadowBluetoothAdapter.clearSupportedProfiles();
+ mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID);
+ when(mHearingAidProfile.getConnectedDevices()).thenReturn(new ArrayList<>(
+ Collections.singletonList(mBluetoothDevice)));
+
+ assertThat(mHelper.getConnectedHearingAidDevice()).isEqualTo(mCachedBluetoothDevice);
+ assertThat(mCachedBluetoothDevice.getAddress()).isEqualTo(mBluetoothDevice.getAddress());
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
similarity index 70%
rename from tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
index 105da65..4decf68 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceAudioRoutingBasePreferenceControllerTest.java
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -37,9 +38,15 @@
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
+import com.android.settings.bluetooth.Utils;
+import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.HearingAidAudioRoutingConstants;
import com.android.settingslib.bluetooth.HearingAidAudioRoutingHelper;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import org.junit.Before;
import org.junit.Rule;
@@ -50,11 +57,13 @@
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
import java.util.List;
/** Tests for {@link HearingDeviceAudioRoutingBasePreferenceController}. */
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class, ShadowBluetoothUtils.class})
public class HearingDeviceAudioRoutingBasePreferenceControllerTest {
@Rule
@@ -63,17 +72,25 @@
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
private static final String TEST_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1";
- private static final String FAKE_KEY = "fake_key";
+ private final ListPreference mListPreference = new ListPreference(mContext);
@Mock
+ private LocalBluetoothManager mLocalBluetoothManager;
+ @Mock
+ private LocalBluetoothProfileManager mLocalBluetoothProfileManager;
+ @Mock
+ private CachedBluetoothDeviceManager mCachedDeviceManager;
+ @Mock
private AudioProductStrategy mAudioProductStrategyMedia;
@Mock
private CachedBluetoothDevice mCachedBluetoothDevice;
@Mock
private BluetoothDevice mBluetoothDevice;
@Spy
- private HearingAidAudioRoutingHelper mHelper = new HearingAidAudioRoutingHelper(mContext);
- private final ListPreference mListPreference = new ListPreference(mContext);
+ private HearingAidAudioRoutingHelper mAudioRoutingHelper =
+ new HearingAidAudioRoutingHelper(mContext);
+ @Mock
+ private HearingAidHelper mHearingAidHelper;
private TestHearingDeviceAudioRoutingBasePreferenceController mController;
@Before
@@ -83,19 +100,23 @@
AudioDeviceInfo.TYPE_HEARING_AID,
TEST_DEVICE_ADDRESS);
+ ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
+ mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
+ when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager);
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
when(mBluetoothDevice.getAnonymizedAddress()).thenReturn(TEST_DEVICE_ADDRESS);
when(mCachedBluetoothDevice.getAddress()).thenReturn(TEST_DEVICE_ADDRESS);
- when(mHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(hearingDeviceAttribute);
+ doReturn(hearingDeviceAttribute).when(
+ mAudioRoutingHelper).getMatchedHearingDeviceAttributes(any());
when(mAudioProductStrategyMedia.getAudioAttributesForLegacyStreamType(
- AudioManager.STREAM_MUSIC))
- .thenReturn((new AudioAttributes.Builder()).build());
- when(mHelper.getAudioProductStrategies()).thenReturn(List.of(mAudioProductStrategyMedia));
+ AudioManager.STREAM_MUSIC)).thenReturn((new AudioAttributes.Builder()).build());
+ when(mAudioRoutingHelper.getAudioProductStrategies()).thenReturn(
+ List.of(mAudioProductStrategyMedia));
- mController = new TestHearingDeviceAudioRoutingBasePreferenceController(mContext, FAKE_KEY,
- mHelper);
- TestHearingDeviceAudioRoutingBasePreferenceController.setupForTesting(
- mCachedBluetoothDevice);
+ mController = new TestHearingDeviceAudioRoutingBasePreferenceController(mContext,
+ "test_key",
+ mAudioRoutingHelper, mHearingAidHelper);
mListPreference.setEntries(R.array.bluetooth_audio_routing_titles);
mListPreference.setEntryValues(R.array.bluetooth_audio_routing_values);
mListPreference.setSummary("%s");
@@ -122,20 +143,21 @@
@Test
public void onPreferenceChange_noMatchedDeviceAttributes_notCallSetStrategies() {
- when(mHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(null);
+ when(mAudioRoutingHelper.getMatchedHearingDeviceAttributes(any())).thenReturn(null);
- verify(mHelper, never()).setPreferredDeviceRoutingStrategies(any(), isNull(), anyInt());
+ verify(mAudioRoutingHelper, never()).setPreferredDeviceRoutingStrategies(any(), isNull(),
+ anyInt());
}
private static class TestHearingDeviceAudioRoutingBasePreferenceController extends
HearingDeviceAudioRoutingBasePreferenceController {
- private static CachedBluetoothDevice sCachedBluetoothDevice;
private static int sSavedRoutingValue;
TestHearingDeviceAudioRoutingBasePreferenceController(Context context,
- String preferenceKey, HearingAidAudioRoutingHelper helper) {
- super(context, preferenceKey, helper);
+ String preferenceKey, HearingAidAudioRoutingHelper audioRoutingHelper,
+ HearingAidHelper hearingAidHelper) {
+ super(context, preferenceKey, audioRoutingHelper, hearingAidHelper);
}
@Override
@@ -144,11 +166,6 @@
}
@Override
- protected CachedBluetoothDevice getHearingDevice() {
- return sCachedBluetoothDevice;
- }
-
- @Override
protected void saveRoutingValue(Context context, int routingValue) {
sSavedRoutingValue = routingValue;
}
@@ -157,9 +174,5 @@
protected int restoreRoutingValue(Context context) {
return sSavedRoutingValue;
}
-
- public static void setupForTesting(CachedBluetoothDevice cachedBluetoothDevice) {
- sCachedBluetoothDevice = cachedBluetoothDevice;
- }
}
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceControllerTest.java
similarity index 97%
rename from tests/robotests/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceControllerTest.java
rename to tests/robotests/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceControllerTest.java
index dec4cc4..8eed294 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/HearingDeviceCallRoutingPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/HearingDeviceCallRoutingPreferenceControllerTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.settings.bluetooth;
+package com.android.settings.accessibility;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
diff --git a/tests/robotests/src/com/android/settings/accounts/ContactSearchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/ContactSearchPreferenceControllerTest.java
index c8606e1..bc65563 100644
--- a/tests/robotests/src/com/android/settings/accounts/ContactSearchPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/ContactSearchPreferenceControllerTest.java
@@ -20,13 +20,19 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.UserInfo;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
+import androidx.test.core.app.ApplicationProvider;
+
import com.android.settingslib.RestrictedSwitchPreference;
import org.junit.Before;
@@ -35,39 +41,51 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
+
+import java.util.Collections;
@RunWith(RobolectricTestRunner.class)
public class ContactSearchPreferenceControllerTest {
private static final String PREF_KEY = "contacts_search";
-
- @Mock
- private UserHandle mManagedUser;
+ private static final int MANAGED_USER_ID = 10;
private Context mContext;
private ContactSearchPreferenceController mController;
private RestrictedSwitchPreference mPreference;
+ @Mock
+ private UserHandle mManagedUser;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private UserInfo mUserInfo;
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
- mController = new ContactSearchPreferenceController(mContext, PREF_KEY);
- mController.setManagedUser(mManagedUser);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
mPreference = spy(new RestrictedSwitchPreference(mContext));
+ when(mUserInfo.isManagedProfile()).thenReturn(true);
+ when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
+ when(mUserManager.getProcessUserId()).thenReturn(0);
+ when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser));
+ when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
+ mController = new ContactSearchPreferenceController(mContext, PREF_KEY);
}
@Test
public void getAvailabilityStatus_noManagedUser_DISABLED() {
- mController.setManagedUser(null);
+ when(mUserManager.getProcessUserId()).thenReturn(MANAGED_USER_ID);
+ mController = new ContactSearchPreferenceController(mContext, PREF_KEY);
+
assertThat(mController.getAvailabilityStatus())
.isNotEqualTo(ContactSearchPreferenceController.AVAILABLE);
}
@Test
public void getAvailabilityStatus_hasManagedUser_AVAILABLE() {
- mController.setManagedUser(mManagedUser);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(ContactSearchPreferenceController.AVAILABLE);
}
@@ -75,32 +93,96 @@
@Test
public void updateState_shouldRefreshContent() {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
- MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, mManagedUser.getIdentifier());
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, MANAGED_USER_ID);
+
mController.updateState(mPreference);
+
assertThat(mPreference.isChecked()).isFalse();
Settings.Secure.putIntForUser(mContext.getContentResolver(),
- MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, mManagedUser.getIdentifier());
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, MANAGED_USER_ID);
+
mController.updateState(mPreference);
+
assertThat(mPreference.isChecked()).isTrue();
}
@Test
public void updateState_preferenceShouldBeDisabled() {
mController.updateState(mPreference);
+
verify(mPreference).setDisabledByAdmin(any());
}
@Test
public void onPreferenceChange_shouldUpdateProviderValue() {
mController.onPreferenceChange(mPreference, false);
+
assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
- MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, mManagedUser.getIdentifier()))
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, MANAGED_USER_ID))
.isEqualTo(0);
mController.onPreferenceChange(mPreference, true);
+
assertThat(Settings.Secure.getIntForUser(mContext.getContentResolver(),
- MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, mManagedUser.getIdentifier()))
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, MANAGED_USER_ID))
.isEqualTo(1);
}
-}
\ No newline at end of file
+
+ @Test
+ public void onQuietModeDisabled_preferenceEnabled() {
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void onQuietModeEnabled_preferenceDisabledAndUnchecked() {
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void afterQuietModeTurnedOnAndOffWhenPreferenceChecked_toggleCheckedAndEnabled() {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 1, MANAGED_USER_ID);
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ assertThat(mPreference.isChecked()).isFalse();
+
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void afterQuietModeTurnedOnAndOffWhenPreferenceUnchecked_toggleUncheckedAndEnabled() {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ MANAGED_PROFILE_CONTACT_REMOTE_SEARCH, 0, MANAGED_USER_ID);
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(true);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ assertThat(mPreference.isChecked()).isFalse();
+
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(false);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java b/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java
new file mode 100644
index 0000000..2698efa
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.accounts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.lifecycle.LifecycleRegistry;
+import androidx.test.core.app.ApplicationProvider;
+
+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.util.Collections;
+
+
+@RunWith(RobolectricTestRunner.class)
+public class ManagedProfileQuietModeEnablerTest {
+ private static final int MANAGED_USER_ID = 10;
+ private Context mContext;
+ private ManagedProfileQuietModeEnabler mQuietModeEnabler;
+ private LifecycleOwner mLifecycleOwner = new LifecycleOwner() {
+ public LifecycleRegistry registry = new LifecycleRegistry(this);
+
+ @Override
+ public Lifecycle getLifecycle() {
+ return registry;
+ }
+ };
+
+ @Mock
+ private ManagedProfileQuietModeEnabler.QuietModeChangeListener mOnQuietModeChangeListener;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private UserHandle mManagedUser;
+ @Mock
+ private UserInfo mUserInfo;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ when(mUserInfo.isManagedProfile()).thenReturn(true);
+ when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
+ when(mUserManager.getProcessUserId()).thenReturn(0);
+ when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
+ when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser));
+ mQuietModeEnabler = new ManagedProfileQuietModeEnabler(mContext,
+ mOnQuietModeChangeListener);
+ }
+
+ @Test
+ public void onSetQuietMode_shouldRequestQuietModeEnabled() {
+ mQuietModeEnabler.setQuietModeEnabled(false);
+ verify(mUserManager).requestQuietModeEnabled(false, mManagedUser);
+ mQuietModeEnabler.setQuietModeEnabled(true);
+ verify(mUserManager).requestQuietModeEnabled(true, mManagedUser);
+ }
+
+ @Test
+ public void onIsQuietModeEnabled_shouldCallIsQuietModeEnabled() {
+ assertThat(mQuietModeEnabler.isQuietModeEnabled()).isEqualTo(
+ verify(mUserManager).isQuietModeEnabled(any()));
+ }
+
+ @Test
+ public void onQuietModeChanged_listenerNotified() {
+ mQuietModeEnabler.onStart(mLifecycleOwner);
+ mContext.sendBroadcast(new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABLE).putExtra(
+ Intent.EXTRA_USER_HANDLE, MANAGED_USER_ID));
+ mContext.sendBroadcast(new Intent(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE).putExtra(
+ Intent.EXTRA_USER_HANDLE, MANAGED_USER_ID));
+ verify(mOnQuietModeChangeListener, times(2)).onQuietModeChanged();
+ }
+
+ @Test
+ public void onStart_shouldRegisterReceiver() {
+ mQuietModeEnabler.onStart(mLifecycleOwner);
+ verify(mContext).registerReceiver(eq(mQuietModeEnabler.mReceiver), any(), anyInt());
+ }
+
+ @Test
+ public void onStop_shouldUnregisterReceiver() {
+ // register it first
+ mContext.registerReceiver(mQuietModeEnabler.mReceiver, null,
+ Context.RECEIVER_EXPORTED/*UNAUDITED*/);
+
+ mQuietModeEnabler.onStop(mLifecycleOwner);
+ verify(mContext).unregisterReceiver(mQuietModeEnabler.mReceiver);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java
index 2a28318..e862d10 100644
--- a/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java
@@ -19,18 +19,18 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
-import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
-import com.android.settings.R;
+import com.android.settingslib.widget.MainSwitchPreference;
import org.junit.Before;
import org.junit.Test;
@@ -38,43 +38,51 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
+
+import java.util.Collections;
@RunWith(RobolectricTestRunner.class)
public class WorkModePreferenceControllerTest {
private static final String PREF_KEY = "work_mode";
+ private static final int MANAGED_USER_ID = 10;
+
+ private Context mContext;
+ private WorkModePreferenceController mController;
+ private MainSwitchPreference mPreference;
@Mock
private UserManager mUserManager;
@Mock
private UserHandle mManagedUser;
-
- private Context mContext;
- private WorkModePreferenceController mController;
- private SwitchPreference mPreference;
+ @Mock
+ private UserInfo mUserInfo;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = spy(RuntimeEnvironment.application);
- when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
-
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+ mPreference = new MainSwitchPreference(mContext);
+ when(mUserInfo.isManagedProfile()).thenReturn(true);
+ when(mUserManager.getUserInfo(anyInt())).thenReturn(mUserInfo);
+ when(mUserManager.getProcessUserId()).thenReturn(0);
+ when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser));
+ when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID);
mController = new WorkModePreferenceController(mContext, PREF_KEY);
- mController.setManagedUser(mManagedUser);
- mPreference = new SwitchPreference(mContext);
}
@Test
public void getAvailabilityStatus_noManagedUser_DISABLED() {
- mController.setManagedUser(null);
+ when(mUserManager.getProcessUserId()).thenReturn(MANAGED_USER_ID);
+ mController = new WorkModePreferenceController(mContext, PREF_KEY);
+
assertThat(mController.getAvailabilityStatus())
.isNotEqualTo(WorkModePreferenceController.AVAILABLE);
}
@Test
public void getAvailabilityStatus_hasManagedUser_AVAILABLE() {
- mController.setManagedUser(mManagedUser);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(WorkModePreferenceController.AVAILABLE);
}
@@ -83,41 +91,29 @@
public void updateState_shouldRefreshContent() {
when(mUserManager.isQuietModeEnabled(any(UserHandle.class)))
.thenReturn(false);
+
mController.updateState(mPreference);
+
assertThat(mPreference.isChecked()).isTrue();
- assertThat(mPreference.getSummary())
- .isEqualTo(mContext.getText(R.string.work_mode_on_summary));
when(mUserManager.isQuietModeEnabled(any(UserHandle.class)))
.thenReturn(true);
+
mController.updateState(mPreference);
+
assertThat(mPreference.isChecked()).isFalse();
- assertThat(mPreference.getSummary())
- .isEqualTo(mContext.getText(R.string.work_mode_off_summary));
}
@Test
public void onPreferenceChange_shouldRequestQuietModeEnabled() {
+ mController.setPreference(mPreference);
+
mController.onPreferenceChange(mPreference, true);
+
verify(mUserManager).requestQuietModeEnabled(false, mManagedUser);
mController.onPreferenceChange(mPreference, false);
+
verify(mUserManager).requestQuietModeEnabled(true, mManagedUser);
}
-
- @Test
- public void onStart_shouldRegisterReceiver() {
- mController.onStart();
- verify(mContext).registerReceiver(eq(mController.mReceiver), any(), anyInt());
- }
-
- @Test
- public void onStop_shouldUnregisterReceiver() {
- // register it first
- mContext.registerReceiver(mController.mReceiver, null,
- Context.RECEIVER_EXPORTED/*UNAUDITED*/);
-
- mController.onStop();
- verify(mContext).unregisterReceiver(mController.mReceiver);
- }
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
index 7282be3..959c642 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintEnrollEnrollingTest.java
@@ -53,7 +53,6 @@
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Vibrator;
-import android.util.FeatureFlagUtils;
import android.view.Display;
import android.view.Surface;
import android.view.View;
@@ -203,8 +202,6 @@
@Test
public void fingerprintUdfpsOverlayEnrollment_showOverlayPortrait() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
@@ -216,8 +213,6 @@
@Test
public void fingerprintUdfpsOverlayEnrollment_showOverlayLandscape() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_90);
@@ -229,8 +224,6 @@
@Test
public void fingerprintUdfpsOverlayEnrollment_usesCorrectProgressBarFillColor() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
final TypedArray ta = mActivity.obtainStyledAttributes(null,
R.styleable.BiometricsEnrollView, R.attr.biometricsEnrollStyle,
@@ -250,9 +243,7 @@
@Test
public void fingerprintUdfpsOverlayEnrollment_checkViewOverlapPortrait() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
- when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_90);
+ when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
final GlifLayout defaultLayout = mActivity.findViewById(R.id.setup_wizard_layout);
@@ -294,9 +285,9 @@
udfpsEnrollView.getViewTreeObserver().addOnDrawListener(() -> {
udfpsEnrollView.getLocationOnScreen(udfpsEnrollViewPosition);
rectUdfpsEnrollView.set(new Rect(udfpsEnrollViewPosition[0],
- udfpsEnrollViewPosition[1], udfpsEnrollViewPosition[0]
- + udfpsEnrollView.getWidth(), udfpsEnrollViewPosition[1]
- + udfpsEnrollView.getHeight()));
+ udfpsEnrollViewPosition[1], udfpsEnrollViewPosition[0]
+ + udfpsEnrollView.getWidth(), udfpsEnrollViewPosition[1]
+ + udfpsEnrollView.getHeight()));
});
lottieAnimationContainer.getViewTreeObserver().addOnDrawListener(() -> {
@@ -321,9 +312,35 @@
}
@Test
+ public void fingerprintUdfpsOverlayEnrollment_descriptionViewGoneWithOverlap() {
+ initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL);
+ doReturn(true).when(mActivity).hasOverlap(any(), any());
+ when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
+ createActivity();
+
+ final GlifLayout defaultLayout = spy(mActivity.findViewById(R.id.setup_wizard_layout));
+ final TextView descriptionTextView = defaultLayout.getDescriptionTextView();
+
+ defaultLayout.getViewTreeObserver().dispatchOnDraw();
+ assertThat(descriptionTextView.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
+ public void fingerprintUdfpsOverlayEnrollment_descriptionViewVisibleWithoutOverlap() {
+ initializeActivityWithoutCreate(TYPE_UDFPS_OPTICAL);
+ doReturn(false).when(mActivity).hasOverlap(any(), any());
+ when(mMockDisplay.getRotation()).thenReturn(Surface.ROTATION_0);
+ createActivity();
+
+ final GlifLayout defaultLayout = spy(mActivity.findViewById(R.id.setup_wizard_layout));
+ final TextView descriptionTextView = defaultLayout.getDescriptionTextView();
+
+ defaultLayout.getViewTreeObserver().dispatchOnDraw();
+ assertThat(descriptionTextView.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
public void forwardEnrollProgressEvents() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity);
@@ -337,8 +354,6 @@
@Test
public void forwardEnrollHelpEvents() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity);
@@ -352,8 +367,6 @@
@Test
public void forwardEnrollAcquiredEvents() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity);
@@ -368,8 +381,6 @@
@Test
public void forwardEnrollPointerDownEvents() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity);
@@ -383,8 +394,6 @@
@Test
public void forwardEnrollPointerUpEvents() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_SHOW_UDFPS_ENROLL_IN_SETTINGS, true);
initializeActivityFor(TYPE_UDFPS_OPTICAL);
EnrollListener listener = new EnrollListener(mActivity);
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 2bc81e6..18b05ad 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
@@ -20,8 +20,11 @@
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment;
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.ADD_FINGERPRINT_REQUEST;
+import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.CHOOSE_LOCK_GENERIC_REQUEST;
import static com.android.settings.biometrics.fingerprint.FingerprintSettings.FingerprintSettingsFragment.KEY_FINGERPRINT_ADD;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
@@ -54,6 +57,7 @@
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.shadow.ShadowFragment;
+import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowSettingsPreferenceFragment;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.testutils.shadow.ShadowUtils;
@@ -63,6 +67,7 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -74,7 +79,7 @@
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowSettingsPreferenceFragment.class, ShadowUtils.class, ShadowFragment.class,
- ShadowUserManager.class})
+ ShadowUserManager.class, ShadowLockPatternUtils.class})
public class FingerprintSettingsFragmentTest {
private FingerprintSettingsFragment mFragment;
private Context mContext;
@@ -92,10 +97,62 @@
doReturn(true).when(mFingerprintManager).isHardwareDetected();
ShadowUtils.setFingerprintManager(mFingerprintManager);
FakeFeatureFactory.setupForTest();
+ }
+ @After
+ public void tearDown() {
+ ShadowUtils.reset();
+ }
+
+ @Test
+ public void testAddFingerprint_inFullScreen_noDialog() {
+ setUpFragment(false);
+ // Click "Add Fingerprint"
+ final Preference preference = new Preference(mContext);
+ preference.setKey(KEY_FINGERPRINT_ADD);
+ mFragment.onPreferenceTreeClick(preference);
+
+ verify(mFragment).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
+ verify(mFragmentTransaction, never()).add(any(),
+ eq(BiometricsSplitScreenDialog.class.getName()));
+
+ }
+
+ @Test
+ public void testAddFingerprint_inMultiWindow_showsDialog() {
+ setUpFragment(false);
+
+ doReturn(true).when(mActivity).isInMultiWindowMode();
+
+ // Click "Add Fingerprint"
+ final Preference preference = new Preference(mContext);
+ preference.setKey(KEY_FINGERPRINT_ADD);
+ mFragment.onPreferenceTreeClick(preference);
+
+ verify(mFragment, times(0)).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
+ verify(mFragmentTransaction).add(any(), eq(BiometricsSplitScreenDialog.class.getName()));
+ }
+
+ @Test
+ public void testChooseLockKeyForFingerprint() {
+ setUpFragment(true);
+ ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(
+ Intent.class);
+ verify(mFragment).startActivityForResult(intentArgumentCaptor.capture(),
+ eq(CHOOSE_LOCK_GENERIC_REQUEST));
+
+ Intent intent = intentArgumentCaptor.getValue();
+ assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
+ false)).isTrue();
+ }
+
+ private void setUpFragment(boolean showChooseLock) {
Intent intent = new Intent();
- intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
- intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 1L);
+ if (!showChooseLock) {
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0]);
+ intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_GK_PW_HANDLE, 1L);
+ }
+
mActivity = spy(Robolectric.buildActivity(FragmentActivity.class, intent).get());
mContext = spy(ApplicationProvider.getApplicationContext());
@@ -112,49 +169,12 @@
doNothing().when(mFragment).startActivityForResult(any(Intent.class), anyInt());
setSensor();
- }
- @After
- public void tearDown() {
- ShadowUtils.reset();
- }
-
- @Test
- public void testAddFingerprint_inFullScreen_noDialog() {
// Start fragment
mFragment.onAttach(mContext);
mFragment.onCreate(null);
mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY);
mFragment.onResume();
-
- // Click "Add Fingerprint"
- final Preference preference = new Preference(mContext);
- preference.setKey(KEY_FINGERPRINT_ADD);
- mFragment.onPreferenceTreeClick(preference);
-
- verify(mFragment).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
- verify(mFragmentTransaction, never()).add(any(),
- eq(BiometricsSplitScreenDialog.class.getName()));
-
- }
-
- @Test
- public void testAddFingerprint_inMultiWindow_showsDialog() {
- // Start fragment
- mFragment.onAttach(mContext);
- mFragment.onCreate(null);
- mFragment.onCreateView(LayoutInflater.from(mContext), mock(ViewGroup.class), Bundle.EMPTY);
- mFragment.onResume();
-
- doReturn(true).when(mActivity).isInMultiWindowMode();
-
- // Click "Add Fingerprint"
- final Preference preference = new Preference(mContext);
- preference.setKey(KEY_FINGERPRINT_ADD);
- mFragment.onPreferenceTreeClick(preference);
-
- verify(mFragment, times(0)).startActivityForResult(any(), eq(ADD_FINGERPRINT_REQUEST));
- verify(mFragmentTransaction).add(any(), eq(BiometricsSplitScreenDialog.class.getName()));
}
private void setSensor() {
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingControllerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingControllerTest.java
deleted file mode 100644
index ea65856..0000000
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingControllerTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.settings.bluetooth;
-
-import static com.android.settings.bluetooth.BluetoothDetailsAudioRoutingController.KEY_AUDIO_ROUTING;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.util.FeatureFlagUtils;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceCategory;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.robolectric.RobolectricTestRunner;
-
-/** Tests for {@link BluetoothDetailsAudioRoutingController}. */
-@RunWith(RobolectricTestRunner.class)
-public class BluetoothDetailsAudioRoutingControllerTest extends
- BluetoothDetailsControllerTestBase {
- @Rule
- public final MockitoRule mockito = MockitoJUnit.rule();
-
- private static final String TEST_ADDRESS = "55:66:77:88:99:AA";
-
- private BluetoothDetailsAudioRoutingController mController;
-
- @Override
- public void setUp() {
- super.setUp();
-
- mController = new BluetoothDetailsAudioRoutingController(mContext, mFragment, mCachedDevice,
- mLifecycle);
- final PreferenceCategory preferenceCategory = new PreferenceCategory(mContext);
- preferenceCategory.setKey(mController.getPreferenceKey());
- mScreen.addPreference(preferenceCategory);
- }
-
- @Test
- public void isAvailable_isHearingAidDevice_available() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true);
- when(mCachedDevice.isHearingAidDevice()).thenReturn(true);
-
- assertThat(mController.isAvailable()).isTrue();
- }
-
- @Test
- public void isAvailable_isNotHearingAidDevice_notAvailable() {
- FeatureFlagUtils.setEnabled(mContext,
- FeatureFlagUtils.SETTINGS_AUDIO_ROUTING, true);
- when(mCachedDevice.isHearingAidDevice()).thenReturn(false);
-
- assertThat(mController.isAvailable()).isFalse();
- }
-
- @Test
- public void init_isHearingAidDevice_expectedAudioRoutingPreference() {
- when(mCachedDevice.isHearingAidDevice()).thenReturn(true);
- when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS);
-
- mController.init(mScreen);
- final Preference preference = mScreen.findPreference(KEY_AUDIO_ROUTING);
- final String address = preference.getExtras().getString(
- BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS);
- final String fragment = preference.getFragment();
-
- assertThat(address).isEqualTo(TEST_ADDRESS);
- assertThat(fragment).isEqualTo(BluetoothDetailsAudioRoutingFragment.class.getName());
-
- }
-}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragmentTest.java
deleted file mode 100644
index 9bd4f1b..0000000
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDetailsAudioRoutingFragmentTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * 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.
- */
-
-package com.android.settings.bluetooth;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.when;
-
-import android.bluetooth.BluetoothDevice;
-import android.content.Context;
-import android.os.Bundle;
-
-import androidx.test.core.app.ApplicationProvider;
-
-import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
-import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
-import com.android.settingslib.bluetooth.LocalBluetoothManager;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.annotation.Config;
-
-/** Tests for {@link BluetoothDetailsAudioRoutingFragment}. */
-@RunWith(RobolectricTestRunner.class)
-@Config(shadows = {ShadowBluetoothUtils.class})
-public class BluetoothDetailsAudioRoutingFragmentTest {
-
- @Rule
- public MockitoRule mMockitoRule = MockitoJUnit.rule();
-
- private static final String TEST_ADDRESS = "55:66:77:88:99:AA";
-
- private final Context mContext = ApplicationProvider.getApplicationContext();
-
- private BluetoothDetailsAudioRoutingFragment mFragment;
- @Mock
- private LocalBluetoothManager mLocalBluetoothManager;
- @Mock
- private CachedBluetoothDeviceManager mCachedDeviceManager;
- @Mock
- private LocalBluetoothAdapter mLocalBluetoothAdapter;
- @Mock
- private BluetoothDevice mBluetoothDevice;
- @Mock
- private CachedBluetoothDevice mCachedDevice;
-
- @Before
- public void setUp() {
- setupEnvironment();
-
- when(mLocalBluetoothAdapter.getRemoteDevice(TEST_ADDRESS)).thenReturn(mBluetoothDevice);
- when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS);
- when(mCachedDeviceManager.findDevice(mBluetoothDevice)).thenReturn(mCachedDevice);
-
- mFragment = new BluetoothDetailsAudioRoutingFragment();
- }
-
- @Test
- public void onAttach_setArgumentsWithAddress_expectedCachedDeviceWithAddress() {
- final Bundle args = new Bundle();
- args.putString(BluetoothDeviceDetailsFragment.KEY_DEVICE_ADDRESS, TEST_ADDRESS);
- mFragment.setArguments(args);
-
- mFragment.onAttach(mContext);
-
- assertThat(mFragment.mCachedDevice.getAddress()).isEqualTo(TEST_ADDRESS);
- }
-
- private void setupEnvironment() {
- ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
- when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(mCachedDeviceManager);
- when(mLocalBluetoothManager.getBluetoothAdapter()).thenReturn(mLocalBluetoothAdapter);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java b/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java
index 314f8c3..de380c4 100644
--- a/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java
@@ -81,9 +81,10 @@
// since GraphicsEnvironment is mocked in Robolectric test environment,
// we will override the system property persist.graphics.egl as if it is changed by
// mGraphicsEnvironment.toggleAngleAsSystemDriver(true).
- // TODO: b/270994705 yuxinhu:
- // add test coverage to test mGraphicsEnvironment.toggleAngleAsSystemDriver()
- // works properly on Android devices / emulators.
+
+ // for test that actually verifies mGraphicsEnvironment.toggleAngleAsSystemDriver(true)
+ // on a device/emulator, please refer to
+ // GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, ANGLE_DRIVER_SUFFIX);
mController.onPreferenceChange(mPreference, true);
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
@@ -97,9 +98,10 @@
// since GraphicsEnvironment is mocked in Robolectric test environment,
// we will override the system property persist.graphics.egl as if it is changed by
// mGraphicsEnvironment.toggleAngleAsSystemDriver(false).
- // TODO: b/270994705 yuxinhu:
- // add test coverage to test mGraphicsEnvironment.toggleAngleAsSystemDriver()
- // works properly on Android devices / emulators.
+
+ // for test that actually verifies mGraphicsEnvironment.toggleAngleAsSystemDriver(true)
+ // on a device/emulator, please refer to
+ // GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
mController.onPreferenceChange(mPreference, false);
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
@@ -124,20 +126,14 @@
@Test
public void updateState_angleSupported_angleUsed_preferenceShouldBeChecked() {
ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
- // TODO: b/270994705 yuxinhu:
- // add test coverage to test mGraphicsEnvironment.toggleAngleAsSystemDriver()
- // works properly on Android devices / emulators.
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, ANGLE_DRIVER_SUFFIX);
mController.updateState(mPreference);
- verify(mPreference).setChecked(true); //false
+ verify(mPreference).setChecked(true);
}
@Test
public void updateState_angleSupported_angleNotUsed_preferenceShouldNotBeChecked() {
ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
- // TODO: b/270994705 yuxinhu:
- // add test coverage to test mGraphicsEnvironment.toggleAngleAsSystemDriver(false)
- // works properly on Android devices / emulators.
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
index 0278553..5e9fb73 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/AdvancedPowerUsageDetailTest.java
@@ -710,7 +710,7 @@
@Test
public void initPreferenceForTriState_isValidPackageName_hasCorrectString() {
- when(mBatteryOptimizeUtils.isValidPackageName()).thenReturn(false);
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
mFragment.initPreferenceForTriState(mContext);
@@ -720,7 +720,7 @@
@Test
public void initPreferenceForTriState_isSystemOrDefaultApp_hasCorrectString() {
- when(mBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
mFragment.initPreferenceForTriState(mContext);
@@ -731,7 +731,7 @@
@Test
public void initPreferenceForTriState_hasCorrectString() {
- when(mBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(false);
mFragment.initPreferenceForTriState(mContext);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
index f3d6816..a800fdb 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBackupHelperTest.java
@@ -70,6 +70,8 @@
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
@@ -84,6 +86,8 @@
private static final int UID1 = 1;
private Context mContext;
+ private PrintWriter mPrintWriter;
+ private StringWriter mStringWriter;
private BatteryBackupHelper mBatteryBackupHelper;
@Mock
@@ -109,6 +113,8 @@
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
+ mStringWriter = new StringWriter();
+ mPrintWriter = new PrintWriter(mStringWriter);
doReturn(mContext).when(mContext).getApplicationContext();
doReturn(mAppOpsManager).when(mContext).getSystemService(AppOpsManager.class);
doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
@@ -126,6 +132,7 @@
@After
public void resetShadows() {
ShadowUserHandle.reset();
+ BatteryBackupHelper.getSharedPreferences(mContext).edit().clear().apply();
}
@Test
@@ -153,34 +160,6 @@
}
@Test
- public void performBackup_oneFullPowerListElement_backupFullPowerListData()
- throws Exception {
- final String[] fullPowerList = {"com.android.package"};
- doReturn(fullPowerList).when(mDeviceController).getFullPowerWhitelist();
-
- mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
-
- final byte[] expectedBytes = fullPowerList[0].getBytes();
- verify(mBackupDataOutput).writeEntityHeader(
- BatteryBackupHelper.KEY_FULL_POWER_LIST, expectedBytes.length);
- verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length);
- }
-
- @Test
- public void performBackup_backupFullPowerListData() throws Exception {
- final String[] fullPowerList = {"com.android.package1", "com.android.package2"};
- doReturn(fullPowerList).when(mDeviceController).getFullPowerWhitelist();
-
- mBatteryBackupHelper.performBackup(null, mBackupDataOutput, null);
-
- final String expectedResult = fullPowerList[0] + DELIMITER + fullPowerList[1];
- final byte[] expectedBytes = expectedResult.getBytes();
- verify(mBackupDataOutput).writeEntityHeader(
- BatteryBackupHelper.KEY_FULL_POWER_LIST, expectedBytes.length);
- verify(mBackupDataOutput).writeEntityData(expectedBytes, expectedBytes.length);
- }
-
- @Test
public void performBackup_nonOwner_ignoreAllBackupAction() throws Exception {
ShadowUserHandle.setUid(1);
final String[] fullPowerList = {"com.android.package"};
@@ -216,6 +195,8 @@
// 2 for UNRESTRICTED mode and 1 for RESTRICTED mode.
final String expectedResult = PACKAGE_NAME1 + ":2," + PACKAGE_NAME2 + ":1,";
verifyBackupData(expectedResult);
+ verifyDumpHistoryData("com.android.testing.1\taction:BACKUP\tevent:mode: 2");
+ verifyDumpHistoryData("com.android.testing.2\taction:BACKUP\tevent:mode: 1");
}
@Test
@@ -232,6 +213,7 @@
// "com.android.testing.2" for RESTRICTED mode.
final String expectedResult = PACKAGE_NAME2 + ":1,";
verifyBackupData(expectedResult);
+ verifyDumpHistoryData("com.android.testing.2\taction:BACKUP\tevent:mode: 1");
}
@Test
@@ -248,6 +230,7 @@
// "com.android.testing.2" for RESTRICTED mode.
final String expectedResult = PACKAGE_NAME2 + ":1,";
verifyBackupData(expectedResult);
+ verifyDumpHistoryData("com.android.testing.2\taction:BACKUP\tevent:mode: 1");
}
@Test
@@ -272,7 +255,7 @@
@Test
public void restoreEntity_incorrectDataKey_notReadBackupData() throws Exception {
- final String incorrectDataKey = BatteryBackupHelper.KEY_FULL_POWER_LIST;
+ final String incorrectDataKey = "incorrect_data_key";
mockBackupData(30 /*dataSize*/, incorrectDataKey);
mBatteryBackupHelper.restoreEntity(mBackupDataInputStream);
@@ -357,6 +340,11 @@
doReturn(dataKey).when(mBackupDataInputStream).getKey();
}
+ private void verifyDumpHistoryData(String expectedResult) {
+ BatteryBackupHelper.dumpHistoricalData(mContext, mPrintWriter);
+ assertThat(mStringWriter.toString().contains(expectedResult)).isTrue();
+ }
+
private void verifyBackupData(String expectedResult) throws Exception {
final byte[] expectedBytes = expectedResult.getBytes();
final ArgumentCaptor<byte[]> captor = ArgumentCaptor.forClass(byte[].class);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
index a829c40..62f812d 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
@@ -69,6 +69,7 @@
mBatteryBroadcastReceiver.mBatteryLevel = BATTERY_INIT_LEVEL;
mBatteryBroadcastReceiver.mBatteryStatus = BATTERY_INIT_STATUS;
mBatteryBroadcastReceiver.mBatteryHealth = BatteryManager.BATTERY_HEALTH_UNKNOWN;
+ mBatteryBroadcastReceiver.mChargingStatus = BatteryManager.CHARGING_POLICY_DEFAULT;
mBatteryBroadcastReceiver.setBatteryChangedListener(mBatteryListener);
mChargingIntent = new Intent(Intent.ACTION_BATTERY_CHANGED);
@@ -91,8 +92,8 @@
@Test
public void onReceive_batteryHealthChanged_dataUpdated() {
- mChargingIntent
- .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+ mChargingIntent.putExtra(
+ BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
mBatteryBroadcastReceiver.onReceive(mContext, mChargingIntent);
assertThat(mBatteryBroadcastReceiver.mBatteryHealth)
@@ -101,6 +102,17 @@
}
@Test
+ public void onReceive_chargingStatusChanged_dataUpdated() {
+ mChargingIntent.putExtra(BatteryManager.EXTRA_CHARGING_STATUS,
+ BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE);
+ mBatteryBroadcastReceiver.onReceive(mContext, mChargingIntent);
+
+ assertThat(mBatteryBroadcastReceiver.mChargingStatus)
+ .isEqualTo(BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE);
+ verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.CHARGING_STATUS);
+ }
+
+ @Test
public void onReceive_batteryNotPresent_shouldShowHelpMessage() {
mChargingIntent.putExtra(BatteryManager.EXTRA_PRESENT, false);
@@ -131,6 +143,8 @@
assertThat(mBatteryBroadcastReceiver.mBatteryStatus).isEqualTo(batteryStatus);
assertThat(mBatteryBroadcastReceiver.mBatteryHealth)
.isEqualTo(BatteryManager.BATTERY_HEALTH_UNKNOWN);
+ assertThat(mBatteryBroadcastReceiver.mChargingStatus)
+ .isEqualTo(BatteryManager.CHARGING_POLICY_DEFAULT);
verify(mBatteryListener, never()).onBatteryChanged(anyInt());
}
@@ -163,6 +177,8 @@
Utils.getBatteryStatus(mContext, mChargingIntent, /* compactStatus= */ false));
assertThat(mBatteryBroadcastReceiver.mBatteryHealth)
.isEqualTo(BatteryManager.BATTERY_HEALTH_UNKNOWN);
+ assertThat(mBatteryBroadcastReceiver.mChargingStatus)
+ .isEqualTo(BatteryManager.CHARGING_POLICY_DEFAULT);
// 2 times because register will force update the battery
verify(mBatteryListener, times(2)).onBatteryChanged(BatteryUpdateType.MANUAL);
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
index f94e5bf..2779e0a 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
@@ -290,8 +290,8 @@
}
@Test
- public void updatePreference_isOverheat_showEmptyText() {
- mBatteryInfo.isOverheated = true;
+ public void updatePreference_isBatteryDefender_showEmptyText() {
+ mBatteryInfo.isBatteryDefender = true;
mController.updateHeaderPreference(mBatteryInfo);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java
index 74f62ad..cb5de7d 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHistoricalLogUtilTest.java
@@ -49,7 +49,7 @@
@Test
public void printHistoricalLog_withDefaultLogs() {
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter);
- assertThat(mTestStringWriter.toString()).contains("No past logs");
+ assertThat(mTestStringWriter.toString()).contains("nothing to dump");
}
@Test
@@ -58,7 +58,7 @@
BatteryHistoricalLogUtil.printBatteryOptimizeHistoricalLog(mContext, mTestPrintWriter);
assertThat(mTestStringWriter.toString()).contains(
- "pkg1\tAction:APPLY\tEvent:logs\tTimestamp:");
+ "pkg1\taction:APPLY\tevent:logs");
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
index eb4b598..b0d6da6 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
@@ -43,7 +43,6 @@
import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.widget.UsageView;
-import com.android.settingslib.R;
import com.android.settingslib.fuelgauge.Estimate;
import org.junit.Before;
@@ -164,26 +163,6 @@
}
@Test
- public void testGetBatteryInfo_basedOnUsageTrueLessThanSevenMinutes_usesCorrectString() {
- Estimate estimate = new Estimate(Duration.ofMinutes(7).toMillis(),
- true /* isBasedOnUsage */,
- 1000 /* averageDischargeTime */);
- BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
- mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
- false /* shortString */);
- BatteryInfo info2 = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
- mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
- true /* shortString */);
-
- // These should be identical in either case
- assertThat(info.remainingLabel.toString()).isEqualTo(
- mContext.getString(R.string.power_remaining_duration_only_shutdown_imminent));
- assertThat(info2.remainingLabel.toString()).isEqualTo(
- mContext.getString(R.string.power_remaining_duration_only_shutdown_imminent));
- assertThat(info2.suggestionLabel).contains(BATTERY_RUN_OUT_PREFIX);
- }
-
- @Test
@Ignore
public void getBatteryInfo_MoreThanOneDay_suggestionLabelIsCorrectString() {
Estimate estimate = new Estimate(Duration.ofDays(3).toMillis(),
@@ -197,25 +176,6 @@
}
@Test
- public void
- testGetBatteryInfo_basedOnUsageTrueBetweenSevenAndFifteenMinutes_usesCorrectString() {
- Estimate estimate = new Estimate(Duration.ofMinutes(10).toMillis(),
- true /* isBasedOnUsage */,
- 1000 /* averageDischargeTime */);
- BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
- mBatteryUsageStats, estimate, SystemClock.elapsedRealtime() * 1000,
- false /* shortString */);
-
- // Check that strings are showing less than 15 minutes remaining regardless of exact time.
- assertThat(info.chargeLabel.toString()).isEqualTo(
- mContext.getString(R.string.power_remaining_less_than_duration,
- FIFTEEN_MIN_FORMATTED, TEST_BATTERY_LEVEL_10));
- assertThat(info.remainingLabel.toString()).isEqualTo(
- mContext.getString(R.string.power_remaining_less_than_duration_only,
- FIFTEEN_MIN_FORMATTED));
- }
-
- @Test
public void testGetBatteryInfo_basedOnUsageFalse_usesDefaultString() {
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mDisChargingBatteryBroadcast,
mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
@@ -254,18 +214,18 @@
}
@Test
- public void testGetBatteryInfo_chargingWithOverheated_updateChargeLabel() {
+ public void testGetBatteryInfo_chargingWithDefender_updateChargeLabel() {
doReturn(TEST_CHARGE_TIME_REMAINING)
.when(mBatteryUsageStats)
.getChargeTimeRemainingMs();
- mChargingBatteryBroadcast
- .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+ mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_CHARGING_STATUS,
+ BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE);
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
false /* shortString */);
- assertThat(info.isOverheated).isTrue();
+ assertThat(info.isBatteryDefender).isTrue();
assertThat(info.chargeLabel.toString()).contains(STATUS_CHARGING_PAUSED);
}
@@ -278,7 +238,8 @@
50 /* level */,
100 /* scale */,
BatteryManager.BATTERY_STATUS_CHARGING)
- .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+ .putExtra(BatteryManager.EXTRA_CHARGING_STATUS,
+ BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE);
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, intent,
mBatteryUsageStats, MOCK_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
@@ -290,8 +251,8 @@
@Test
public void testGetBatteryInfo_dockDefenderTemporarilyBypassed_updateChargeLabel() {
doReturn(REMAINING_TIME).when(mBatteryUsageStats).getChargeTimeRemainingMs();
- mChargingBatteryBroadcast
- .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_GOOD);
+ mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_CHARGING_STATUS,
+ BatteryManager.CHARGING_POLICY_DEFAULT);
Settings.Global.putInt(mContext.getContentResolver(),
BatteryUtils.SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 1);
@@ -309,8 +270,8 @@
@Test
public void testGetBatteryInfo_dockDefenderFutureBypass_updateChargeLabel() {
doReturn(false).when(mFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
- mChargingBatteryBroadcast
- .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_GOOD);
+ mChargingBatteryBroadcast.putExtra(BatteryManager.EXTRA_CHARGING_STATUS,
+ BatteryManager.CHARGING_POLICY_DEFAULT);
BatteryInfo info = BatteryInfo.getBatteryInfo(mContext,
BatteryTestUtils.getCustomBatteryIntent(BatteryManager.BATTERY_PLUGGED_DOCK,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
index 83a75f6..f9d3108 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryOptimizeUtilsTest.java
@@ -136,16 +136,16 @@
}
@Test
- public void testIsValidPackageName_InvalidPackageName_returnFalse() {
+ public void isDisabledForOptimizeModeOnly_invalidPackageName_returnTrue() {
final BatteryOptimizeUtils testBatteryOptimizeUtils =
new BatteryOptimizeUtils(mContext, UID, null);
- assertThat(testBatteryOptimizeUtils.isValidPackageName()).isFalse();
+ assertThat(testBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).isTrue();
}
@Test
- public void testIsValidPackageName_validPackageName_returnTrue() {
- assertThat(mBatteryOptimizeUtils.isValidPackageName()).isTrue();
+ public void isDisabledForOptimizeModeOnly_validPackageName_returnFalse() {
+ assertThat(mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).isFalse();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsMigrateCheckerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsMigrateCheckerTest.java
index dfee3e7..c34dcec 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsMigrateCheckerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsMigrateCheckerTest.java
@@ -18,35 +18,76 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoInteractions;
+
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.os.UserManager;
import com.android.settings.TestUtils;
+import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry;
import com.android.settings.fuelgauge.batterysaver.BatterySaverScheduleRadioButtonsController;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+import java.util.ArrayList;
+import java.util.Arrays;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {BatterySettingsMigrateCheckerTest.ShadowUserHandle.class})
public final class BatterySettingsMigrateCheckerTest {
private static final Intent BOOT_COMPLETED_INTENT =
new Intent(Intent.ACTION_BOOT_COMPLETED);
+ private static final int UID = 2003;
+ private static final String PACKAGE_NAME = "com.android.test.app";
private Context mContext;
private BatterySettingsMigrateChecker mBatterySettingsMigrateChecker;
+ @Mock
+ private PackageManager mPackageManager;
+ @Mock
+ private BatteryOptimizeUtils mBatteryOptimizeUtils;
+
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
+ mContext = spy(RuntimeEnvironment.application);
+ doReturn(mContext).when(mContext).getApplicationContext();
+ doReturn(mPackageManager).when(mContext).getPackageManager();
+ doReturn(UID).when(mPackageManager)
+ .getPackageUid(PACKAGE_NAME, PackageManager.GET_META_DATA);
+ BatterySettingsMigrateChecker.sBatteryOptimizeUtils = mBatteryOptimizeUtils;
mBatterySettingsMigrateChecker = new BatterySettingsMigrateChecker();
}
+ @After
+ public void resetShadows() {
+ ShadowUserHandle.reset();
+ }
+
@Test
public void onReceive_invalidScheduledLevel_resetScheduledValue() {
final int invalidScheduledLevel = 5;
@@ -98,6 +139,54 @@
assertThat(getScheduledLevel()).isEqualTo(invalidScheduledLevel);
}
+ @Test
+ public void onReceive_nonOwner_noAction() {
+ ShadowUserHandle.setUid(1);
+ final int invalidScheduledLevel = 5;
+ setScheduledLevel(invalidScheduledLevel);
+
+ mBatterySettingsMigrateChecker.onReceive(mContext, BOOT_COMPLETED_INTENT);
+
+ assertThat(getScheduledLevel()).isEqualTo(invalidScheduledLevel);
+ }
+
+ @Test
+ public void verifyOptimizationModes_inAllowList_resetOptimizationMode() throws Exception {
+ doReturn(BatteryOptimizeUtils.MODE_RESTRICTED).when(mBatteryOptimizeUtils)
+ .getAppOptimizationMode();
+
+ mBatterySettingsMigrateChecker.verifyOptimizationModes(
+ mContext, Arrays.asList(PACKAGE_NAME));
+
+ final InOrder inOrder = inOrder(mBatteryOptimizeUtils);
+ inOrder.verify(mBatteryOptimizeUtils).getAppOptimizationMode();
+ inOrder.verify(mBatteryOptimizeUtils).setAppUsageState(
+ BatteryOptimizeUtils.MODE_OPTIMIZED,
+ BatteryOptimizeHistoricalLogEntry.Action.FORCE_RESET);
+ }
+
+ @Test
+ public void verifyOptimizationModes_optimizedMode_noAction() throws Exception {
+ doReturn(BatteryOptimizeUtils.MODE_OPTIMIZED).when(mBatteryOptimizeUtils)
+ .getAppOptimizationMode();
+
+ mBatterySettingsMigrateChecker.verifyOptimizationModes(
+ mContext, Arrays.asList(PACKAGE_NAME));
+
+ verify(mBatteryOptimizeUtils, never()).setAppUsageState(anyInt(), any());
+ }
+
+ @Test
+ public void verifyOptimizationModes_notInAllowList_noAction() throws Exception {
+ doReturn(BatteryOptimizeUtils.MODE_RESTRICTED).when(mBatteryOptimizeUtils)
+ .getAppOptimizationMode();
+
+ mBatterySettingsMigrateChecker.verifyOptimizationModes(
+ mContext, new ArrayList<String>());
+
+ verifyNoInteractions(mBatteryOptimizeUtils);
+ }
+
private void setScheduledLevel(int scheduledLevel) {
TestUtils.setScheduledLevel(mContext, scheduledLevel);
}
@@ -105,4 +194,24 @@
private int getScheduledLevel() {
return TestUtils.getScheduledLevel(mContext);
}
+
+ @Implements(UserHandle.class)
+ public static class ShadowUserHandle {
+ // Sets the default as thte OWNER role.
+ private static int sUid = 0;
+
+ public static void setUid(int uid) {
+ sUid = uid;
+ }
+
+ @Implementation
+ public static int myUserId() {
+ return sUid;
+ }
+
+ @Resetter
+ public static void reset() {
+ sUid = 0;
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
index b5f8149..2fe0cec 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
@@ -487,32 +487,32 @@
}
@Test
- public void testIsBatteryDefenderOn_isOverheatedAndIsCharging_returnTrue() {
- mBatteryInfo.isOverheated = true;
+ public void testIsBatteryDefenderOn_isDefenderAndIsCharging_returnTrue() {
+ mBatteryInfo.isBatteryDefender = true;
mBatteryInfo.discharging = false;
assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isTrue();
}
@Test
- public void testIsBatteryDefenderOn_isOverheatedAndDischarging_returnFalse() {
- mBatteryInfo.isOverheated = true;
+ public void testIsBatteryDefenderOn_isDefenderAndDischarging_returnFalse() {
+ mBatteryInfo.isBatteryDefender = true;
mBatteryInfo.discharging = true;
assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isFalse();
}
@Test
- public void testIsBatteryDefenderOn_notOverheatedAndDischarging_returnFalse() {
- mBatteryInfo.isOverheated = false;
+ public void testIsBatteryDefenderOn_notDefenderAndDischarging_returnFalse() {
+ mBatteryInfo.isBatteryDefender = false;
mBatteryInfo.discharging = true;
assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isFalse();
}
@Test
- public void testIsBatteryDefenderOn_notOverheatedAndIsCharging_returnFalse() {
- mBatteryInfo.isOverheated = false;
+ public void testIsBatteryDefenderOn_notDefenderAndIsCharging_returnFalse() {
+ mBatteryInfo.isBatteryDefender = false;
mBatteryInfo.discharging = false;
assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isFalse();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java
index 1fec92a..71bb998 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/OptimizedPreferenceControllerTest.java
@@ -52,7 +52,7 @@
@Test
public void testUpdateState_invalidPackage_prefEnabled() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(false);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
mController.updateState(mPreference);
@@ -62,7 +62,7 @@
@Test
public void testUpdateState_isSystemOrDefaultAppAndOptimizeStates_prefChecked() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
BatteryOptimizeUtils.MODE_OPTIMIZED);
@@ -74,7 +74,7 @@
@Test
public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
mController.updateState(mPreference);
@@ -85,7 +85,7 @@
@Test
public void testUpdateState_isOptimizedStates_prefChecked() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
BatteryOptimizeUtils.MODE_OPTIMIZED);
@@ -96,7 +96,7 @@
@Test
public void testUpdateState_prefUnchecked() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
mController.updateState(mPreference);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedPreferenceControllerTest.java
index 944376c..bcddbc2 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/RestrictedPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/RestrictedPreferenceControllerTest.java
@@ -52,7 +52,7 @@
@Test
public void testUpdateState_isValidPackage_prefEnabled() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
mController.updateState(mPreference);
@@ -61,7 +61,7 @@
@Test
public void testUpdateState_invalidPackage_prefDisabled() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(false);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
mController.updateState(mPreference);
@@ -70,7 +70,7 @@
@Test
public void testUpdateState_isSystemOrDefaultAppAndRestrictedStates_prefChecked() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
BatteryOptimizeUtils.MODE_RESTRICTED);
@@ -82,7 +82,7 @@
@Test
public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
mController.updateState(mPreference);
@@ -93,7 +93,7 @@
@Test
public void testUpdateState_isRestrictedStates_prefChecked() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
BatteryOptimizeUtils.MODE_RESTRICTED);
@@ -104,7 +104,7 @@
@Test
public void testUpdateState_prefUnchecked() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
mController.updateState(mPreference);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java
index c5642df..9bed9ba 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/UnrestrictedPreferenceControllerTest.java
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package com.android.settings.fuelgauge;
import static com.google.common.truth.Truth.assertThat;
@@ -53,7 +52,7 @@
@Test
public void testUpdateState_isValidPackage_prefEnabled() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
mController.updateState(mPreference);
@@ -62,7 +61,7 @@
@Test
public void testUpdateState_invalidPackage_prefDisabled() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(false);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(true);
mController.updateState(mPreference);
@@ -71,7 +70,7 @@
@Test
public void testUpdateState_isSystemOrDefaultAppAndUnrestrictedStates_prefChecked() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
BatteryOptimizeUtils.MODE_UNRESTRICTED);
@@ -83,7 +82,7 @@
@Test
public void testUpdateState_isSystemOrDefaultApp_prefUnchecked() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mockBatteryOptimizeUtils.isSystemOrDefaultApp()).thenReturn(true);
mController.updateState(mPreference);
@@ -94,7 +93,7 @@
@Test
public void testUpdateState_isUnrestrictedStates_prefChecked() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
when(mockBatteryOptimizeUtils.getAppOptimizationMode()).thenReturn(
BatteryOptimizeUtils.MODE_UNRESTRICTED);
@@ -105,7 +104,7 @@
@Test
public void testUpdateState_prefUnchecked() {
- when(mockBatteryOptimizeUtils.isValidPackageName()).thenReturn(true);
+ when(mockBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()).thenReturn(false);
mController.updateState(mPreference);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
index f81a4be..64d5d04 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
@@ -60,32 +60,32 @@
}
@Test
- public void testDetect_notOverheatedNotExtraDefend_tipInvisible() {
- mBatteryInfo.isOverheated = false;
+ public void testDetect_notDefenderNotExtraDefend_tipInvisible() {
+ mBatteryInfo.isBatteryDefender = false;
when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
}
@Test
- public void testDetect_notOverheatedIsExtraDefend_tipInvisible() {
- mBatteryInfo.isOverheated = false;
+ public void testDetect_notDefenderIsExtraDefend_tipInvisible() {
+ mBatteryInfo.isBatteryDefender = false;
when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
}
@Test
- public void testDetect_isOverheatedIsExtraDefend_tipInvisible() {
- mBatteryInfo.isOverheated = false;
+ public void testDetect_isDefenderIsExtraDefend_tipInvisible() {
+ mBatteryInfo.isBatteryDefender = false;
when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
}
@Test
- public void testDetect_isOverheatedNotExtraDefend_tipNew() {
- mBatteryInfo.isOverheated = true;
+ public void testDetect_isDefenderNotExtraDefend_tipNew() {
+ mBatteryInfo.isBatteryDefender = true;
when(mFakeFeatureFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
assertThat(mBatteryDefenderDetector.detect().getState())
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
index 9652a00..bd2c5d1 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/DockDefenderDetectorTest.java
@@ -83,7 +83,7 @@
@Test
public void testDetect_dockDefenderActive() {
- mBatteryInfo.isOverheated = true;
+ mBatteryInfo.isBatteryDefender = true;
doReturn(true).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
BatteryTip batteryTip = mDockDefenderDetector.detect();
@@ -95,7 +95,7 @@
@Test
public void testDetect_dockDefenderFutureBypass() {
- mBatteryInfo.isOverheated = false;
+ mBatteryInfo.isBatteryDefender = false;
doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
BatteryTip batteryTip = mDockDefenderDetector.detect();
@@ -107,7 +107,7 @@
@Test
public void testDetect_overheatedTrue_dockDefenderDisabled() {
- mBatteryInfo.isOverheated = true;
+ mBatteryInfo.isBatteryDefender = true;
doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
BatteryTip batteryTip = mDockDefenderDetector.detect();
@@ -131,7 +131,7 @@
@Test
public void testDetect_overheatedTrueAndDockDefenderNotTriggered_dockDefenderDisabled() {
doReturn(false).when(mFakeFeatureFactory.powerUsageFeatureProvider).isExtraDefend();
- mBatteryInfo.isOverheated = true;
+ mBatteryInfo.isBatteryDefender = true;
BatteryTip batteryTip = mDockDefenderDetector.detect();
diff --git a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
index 111ee5a..16d51be 100644
--- a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
+++ b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java
@@ -18,19 +18,32 @@
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.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.Activity;
+import android.app.IActivityManager;
import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.os.LocaleList;
+import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.FragmentManager;
+import androidx.fragment.app.FragmentTransaction;
import com.android.internal.app.LocaleStore;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
+import com.android.settings.testutils.shadow.ShadowActivityManager;
import com.android.settings.testutils.shadow.ShadowAlertDialogCompat;
import org.junit.After;
@@ -45,22 +58,42 @@
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Locale;
@RunWith(RobolectricTestRunner.class)
-@Config(shadows = ShadowAlertDialogCompat.class)
+@Config(shadows = {ShadowAlertDialogCompat.class, ShadowActivityManager.class})
public class LocaleListEditorTest {
+ private static final String ARG_DIALOG_TYPE = "arg_dialog_type";
+ private static final String TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT = "dialog_confirm_system_default";
+ private static final String TAG_DIALOG_NOT_AVAILABLE = "dialog_not_available_locale";
+ private static final int DIALOG_CONFIRM_SYSTEM_DEFAULT = 1;
+ private static final int REQUEST_CONFIRM_SYSTEM_DEFAULT = 1;
+
private LocaleListEditor mLocaleListEditor;
private Context mContext;
private FragmentActivity mActivity;
+ private List mLocaleList;
+ private Intent mIntent = new Intent();
@Mock
private LocaleDragAndDropAdapter mAdapter;
+ @Mock
+ private LocaleStore.LocaleInfo mLocaleInfo;
+ @Mock
+ private FragmentManager mFragmentManager;
+ @Mock
+ private FragmentTransaction mFragmentTransaction;
+ @Mock
+ private View mView;
+ @Mock
+ private IActivityManager mActivityService;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mLocaleListEditor = spy(new LocaleListEditor());
@@ -74,6 +107,8 @@
ReflectionHelpers.setField(mLocaleListEditor, "mUserManager",
RuntimeEnvironment.application.getSystemService(Context.USER_SERVICE));
ReflectionHelpers.setField(mLocaleListEditor, "mAdapter", mAdapter);
+ ReflectionHelpers.setField(mLocaleListEditor, "mFragmentManager", mFragmentManager);
+ when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction);
FakeFeatureFactory.setupForTest();
}
@@ -174,4 +209,65 @@
assertThat(result.getLocale().getUnicodeLocaleType("fw")).isEqualTo("wed");
assertThat(result.getLocale().getUnicodeLocaleType("mu")).isEqualTo("celsius");
}
+
+ @Test
+ public void onActivityResult_ResultCodeIsOk_showNotAvailableDialog() {
+ Bundle bundle = new Bundle();
+ bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
+ mIntent.putExtras(bundle);
+ setUpLocaleConditions();
+ mLocaleListEditor.onActivityResult(REQUEST_CONFIRM_SYSTEM_DEFAULT, Activity.RESULT_OK,
+ mIntent);
+
+ verify(mFragmentTransaction).add(any(LocaleDialogFragment.class),
+ eq(TAG_DIALOG_NOT_AVAILABLE));
+ }
+
+ @Test
+ public void onActivityResult_ResultCodeIsCancel_notifyAdapterListChanged() {
+ Bundle bundle = new Bundle();
+ bundle.putInt(ARG_DIALOG_TYPE, DIALOG_CONFIRM_SYSTEM_DEFAULT);
+ mIntent.putExtras(bundle);
+ setUpLocaleConditions();
+ mLocaleListEditor.onActivityResult(REQUEST_CONFIRM_SYSTEM_DEFAULT, Activity.RESULT_CANCELED,
+ mIntent);
+
+ verify(mAdapter).notifyListChanged(mLocaleInfo);
+ }
+
+ @Test
+ public void onTouch_dragDifferentLocaleToTop_showConfirmDialog() throws Exception {
+ MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0.0f, 0.0f, 0);
+ setUpLocaleConditions();
+ final Configuration config = new Configuration();
+ config.setLocales((LocaleList.forLanguageTags("zh-TW,en-US")));
+ when(mActivityService.getConfiguration()).thenReturn(config);
+ when(mAdapter.getFeedItemList()).thenReturn(mLocaleList);
+ mLocaleListEditor.onTouch(mView, event);
+
+ verify(mFragmentTransaction).add(any(LocaleDialogFragment.class),
+ eq(TAG_DIALOG_CONFIRM_SYSTEM_DEFAULT));
+ }
+
+ @Test
+ public void onTouch_dragSameLocaleToTop_updateAdapter() throws Exception {
+ MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_UP, 0.0f, 0.0f, 0);
+ setUpLocaleConditions();
+ final Configuration config = new Configuration();
+ config.setLocales((LocaleList.forLanguageTags("en-US,zh-TW")));
+ when(mActivityService.getConfiguration()).thenReturn(config);
+ when(mAdapter.getFeedItemList()).thenReturn(mLocaleList);
+ mLocaleListEditor.onTouch(mView, event);
+
+ verify(mAdapter).doTheUpdate();
+ }
+
+ private void setUpLocaleConditions() {
+ ShadowActivityManager.setService(mActivityService);
+ mLocaleList = new ArrayList<>();
+ mLocaleList.add(mLocaleInfo);
+ when(mLocaleInfo.getFullNameNative()).thenReturn("English");
+ when(mLocaleInfo.getLocale()).thenReturn(LocaleList.forLanguageTags("en-US").get(0));
+ when(mAdapter.getFeedItemList()).thenReturn(mLocaleList);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
index 5310ae0..8d6d2d9 100644
--- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
+++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java
@@ -133,18 +133,12 @@
assertThat(mController.isAvailable()).isFalse();
}
- @Ignore
@Test
- public void getSummary_noSubscriptions_correctSummaryAndClickHandler() {
+ public void getSummary_noSubscriptions_returnSummaryCorrectly() {
mController.displayPreference(mPreferenceScreen);
mController.onResume();
- assertThat(mController.getSummary()).isEqualTo("Add a network");
- final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
- doNothing().when(mContext).startActivity(intentCaptor.capture());
- mPreference.getOnPreferenceClickListener().onPreferenceClick(mPreference);
- assertThat(intentCaptor.getValue().getAction()).isEqualTo(
- EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTION);
+ assertThat(mController.getSummary()).isEqualTo("Add a network");
}
@Test
@@ -300,15 +294,13 @@
assertThat(captor.getValue()).isFalse();
}
- @Ignore
@Test
- public void onResume_noSubscriptionEsimDisabled_isDisabled() {
+ public void onAvailableSubInfoChanged_noSubscriptionEsimDisabled_isDisabled() {
Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0);
- SubscriptionUtil.setAvailableSubscriptionsForTesting(null);
when(mEuiccManager.isEnabled()).thenReturn(false);
mController.displayPreference(mPreferenceScreen);
- mController.onResume();
+ mController.onAvailableSubInfoChanged(null);
assertThat(mPreference.isEnabled()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
index dbc60dc..12a540d 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java
@@ -30,6 +30,8 @@
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_BIOMETRICS;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FACE;
+import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_IS_CALLING_APP_ADMIN;
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
@@ -126,7 +128,9 @@
when(mFaceManager.isHardwareDetected()).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
when(mFakeFeatureFactory.mFaceFeatureProvider.isSetupWizardSupported(any())).thenReturn(
- false);
+ true);
+ ShadowUtils.setFingerprintManager(mFingerprintManager);
+ ShadowUtils.setFaceManager(mFaceManager);
}
@After
@@ -540,35 +544,63 @@
@Test
public void updatePreferenceText_supportBiometrics_showFaceAndFingerprint() {
- ShadowLockPatternUtils.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
- final PasswordPolicy policy = new PasswordPolicy();
- policy.quality = PASSWORD_QUALITY_ALPHABETIC;
- ShadowLockPatternUtils.setRequestedProfilePasswordMetrics(policy.getMinMetrics());
-
+ ShadowStorageManager.setIsFileEncrypted(false);
final Intent intent = new Intent().putExtra(EXTRA_KEY_FOR_BIOMETRICS, true);
initActivity(intent);
- final Intent passwordIntent = mFragment.getLockPatternIntent();
- assertThat(passwordIntent.getIntExtra(ChooseLockPassword.EXTRA_KEY_MIN_COMPLEXITY,
- PASSWORD_COMPLEXITY_NONE)).isEqualTo(PASSWORD_COMPLEXITY_LOW);
final String supportFingerprint = capitalize(mActivity.getResources().getString(
R.string.security_settings_fingerprint));
final String supportFace = capitalize(mActivity.getResources().getString(
R.string.keywords_face_settings));
+ String pinTitle =
+ (String) mFragment.findPreference(ScreenLockType.PIN.preferenceKey).getTitle();
+ String patternTitle =
+ (String) mFragment.findPreference(ScreenLockType.PATTERN.preferenceKey).getTitle();
+ String passwordTitle =
+ (String) mFragment.findPreference(ScreenLockType.PASSWORD.preferenceKey).getTitle();
- assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
- supportFingerprint);
- assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PIN)).contains(
- supportFace);
- assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains(
- supportFingerprint);
- assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PATTERN)).contains(
- supportFace);
- assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains(
- supportFingerprint);
- assertThat(mFragment.getBiometricsPreferenceTitle(ScreenLockType.PASSWORD)).contains(
- supportFace);
+ assertThat(pinTitle).contains(supportFingerprint);
+ assertThat(pinTitle).contains(supportFace);
+ assertThat(patternTitle).contains(supportFingerprint);
+ assertThat(patternTitle).contains(supportFace);
+ assertThat(passwordTitle).contains(supportFingerprint);
+ assertThat(passwordTitle).contains(supportFace);
+ }
+
+ @Test
+ public void updatePreferenceText_supportFingerprint_showFingerprint() {
+ ShadowStorageManager.setIsFileEncrypted(false);
+ final Intent intent = new Intent().putExtra(EXTRA_KEY_FOR_FINGERPRINT, true);
+ initActivity(intent);
+ mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
+
+ assertThat(mFragment.findPreference(ScreenLockType.PIN.preferenceKey).getTitle()).isEqualTo(
+ mFragment.getString(R.string.fingerprint_unlock_set_unlock_pin));
+ assertThat(mFragment.findPreference(
+ ScreenLockType.PATTERN.preferenceKey).getTitle()).isEqualTo(
+ mFragment.getString(R.string.fingerprint_unlock_set_unlock_pattern));
+ assertThat(mFragment.findPreference(
+ ScreenLockType.PASSWORD.preferenceKey).getTitle()).isEqualTo(
+ mFragment.getString(R.string.fingerprint_unlock_set_unlock_password));
+ }
+
+ @Test
+ public void updatePreferenceText_supportFace_showFace() {
+
+ ShadowStorageManager.setIsFileEncrypted(false);
+ final Intent intent = new Intent().putExtra(EXTRA_KEY_FOR_FACE, true);
+ initActivity(intent);
+ mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
+
+ assertThat(mFragment.findPreference(ScreenLockType.PIN.preferenceKey).getTitle()).isEqualTo(
+ mFragment.getString(R.string.face_unlock_set_unlock_pin));
+ assertThat(mFragment.findPreference(
+ ScreenLockType.PATTERN.preferenceKey).getTitle()).isEqualTo(
+ mFragment.getString(R.string.face_unlock_set_unlock_pattern));
+ assertThat(mFragment.findPreference(
+ ScreenLockType.PASSWORD.preferenceKey).getTitle()).isEqualTo(
+ mFragment.getString(R.string.face_unlock_set_unlock_password));
}
private void initActivity(@Nullable Intent intent) {
diff --git a/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
index 65eaddd..e8bd27d 100644
--- a/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/slices/SlicePreferenceControllerTest.java
@@ -18,8 +18,10 @@
import static com.google.common.truth.Truth.assertThat;
+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 android.content.Context;
import android.net.Uri;
@@ -43,11 +45,11 @@
private LiveData<Slice> mLiveData;
@Mock
private SlicePreference mSlicePreference;
+
private Context mContext;
private SlicePreferenceController mController;
private Uri mUri;
-
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -78,11 +80,31 @@
@Test
public void onStop_unregisterObserver() {
+ when(mLiveData.hasActiveObservers()).thenReturn(true);
+ mController.onStart();
+
mController.onStop();
verify(mLiveData).removeObserver(mController);
}
@Test
+ public void onStop_noActiveObservers_notUnregisterObserver() {
+ when(mLiveData.hasActiveObservers()).thenReturn(false);
+ mController.onStart();
+
+ mController.onStop();
+ verify(mLiveData, never()).removeObserver(mController);
+ }
+
+ @Test
+ public void onStop_notRegisterObserver_notUnregisterObserver() {
+ when(mLiveData.hasActiveObservers()).thenReturn(true);
+
+ mController.onStop();
+ verify(mLiveData, never()).removeObserver(mController);
+ }
+
+ @Test
public void onChanged_nullSlice_updateSlice() {
mController.onChanged(null);
diff --git a/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java b/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java
new file mode 100644
index 0000000..3f85535
--- /dev/null
+++ b/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java
@@ -0,0 +1,325 @@
+/*
+ * 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.
+ */
+
+package com.android.settings.development.graphicsdriver;
+
+import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.ANGLE_DRIVER_SUFFIX;
+import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.Injector;
+import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.PROPERTY_PERSISTENT_GRAPHICS_EGL;
+import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.PROPERTY_RO_GFX_ANGLE_SUPPORTED;
+
+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.when;
+
+import android.content.Context;
+import android.os.Looper;
+import android.os.SystemProperties;
+
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.development.DevelopmentSettingsDashboardFragment;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest {
+ private Context mContext;
+ private SwitchPreference mPreference;
+
+ private GraphicsDriverEnableAngleAsSystemDriverController mController;
+
+ @Mock
+ private DevelopmentSettingsDashboardFragment mFragment;
+
+ @Mock
+ private GraphicsDriverSystemPropertiesWrapper mSystemPropertiesMock;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+
+ mContext = ApplicationProvider.getApplicationContext();
+
+ // Construct a GraphicsDriverEnableAngleAsSystemDriverController with two Overrides:
+ // 1) Override the mSystemProperties with mSystemPropertiesMock,
+ // so we can force the SystemProperties with values we need to run tests.
+ // 2) Override the showRebootDialog() to do nothing.
+ // We do not need to pop up the reboot dialog in the test.
+ mController = new GraphicsDriverEnableAngleAsSystemDriverController(
+ mContext, mFragment, new Injector(){
+ @Override
+ public GraphicsDriverSystemPropertiesWrapper createSystemPropertiesWrapper() {
+ return mSystemPropertiesMock;
+ }
+ }) {
+ @Override
+ void showRebootDialog() {
+ // do nothing
+ }
+ };
+
+ final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+ mPreference = new SwitchPreference(mContext);
+ mPreference.setKey(mController.getPreferenceKey());
+ screen.addPreference(mPreference);
+ mController.displayPreference(screen);
+ }
+
+ @Test
+ public void onPreferenceChange_switchOn_shouldEnableAngleAsSystemDriver() {
+ // Add a callback when SystemProperty changes.
+ // This allows the thread to wait until
+ // GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ Runnable countDown = new Runnable() {
+ @Override
+ public void run() {
+ countDownLatch.countDown();
+ }
+ };
+ SystemProperties.addChangeCallback(countDown);
+
+ // Test onPreferenceChange(true) updates the persist.graphics.egl to "angle"
+ mController.onPreferenceChange(mPreference, true);
+ try {
+ countDownLatch.await(100, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+ final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ assertThat(systemEGLDriver).isEqualTo(ANGLE_DRIVER_SUFFIX);
+
+ // Done with the test, remove the callback
+ SystemProperties.removeChangeCallback(countDown);
+ }
+
+ @Test
+ public void onPreferenceChange_switchOff_shouldDisableAngleAsSystemDriver() {
+ // Add a callback when SystemProperty changes.
+ // This allows the thread to wait until
+ // GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ Runnable countDown = new Runnable() {
+ @Override
+ public void run() {
+ countDownLatch.countDown();
+ }
+ };
+ SystemProperties.addChangeCallback(countDown);
+
+ // Test onPreferenceChange(false) updates the persist.graphics.egl to ""
+ mController.onPreferenceChange(mPreference, false);
+ try {
+ countDownLatch.await(100, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+ final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ assertThat(systemEGLDriver).isEqualTo("");
+
+ // Done with the test, remove the callback
+ SystemProperties.removeChangeCallback(countDown);
+ }
+
+ @Test
+ public void updateState_angleNotSupported_PreferenceShouldDisabled() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any())).thenReturn("");
+ mController.updateState(mPreference);
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void updateState_angleNotSupported_PreferenceShouldNotBeChecked() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
+ .thenReturn("");
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void updateState_angleSupported_PreferenceShouldEnabled() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
+ .thenReturn("true");
+ mController.updateState(mPreference);
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void updateState_angleSupported_angleIsSystemGLESDriver_PreferenceShouldBeChecked() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
+ .thenReturn("true");
+ when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
+ .thenReturn(ANGLE_DRIVER_SUFFIX);
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void
+ updateState_angleSupported_angleIsNotSystemGLESDriver_PreferenceShouldNotBeChecked() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
+ .thenReturn("true");
+ when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
+ .thenReturn("");
+ mController.updateState(mPreference);
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void onDeveloperOptionSwitchEnabled_angleSupported_PreferenceShouldEnabled() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
+ .thenReturn("true");
+ mController.onDeveloperOptionsSwitchEnabled();
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void onDeveloperOptionSwitchEnabled_angleNotSupported_PrefenceShouldDisabled() {
+ when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
+ .thenReturn("false");
+ mController.onDeveloperOptionsSwitchEnabled();
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void onDeveloperOptionSwitchDisabled_angleIsNotSystemGLESDriver() {
+ // Add a callback when SystemProperty changes.
+ // This allows the thread to wait until
+ // GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ Runnable countDown = new Runnable() {
+ @Override
+ public void run() {
+ countDownLatch.countDown();
+ }
+ };
+ SystemProperties.addChangeCallback(countDown);
+
+ // Test that onDeveloperOptionSwitchDisabled,
+ // persist.graphics.egl updates to ""
+ mController.onDeveloperOptionsSwitchDisabled();
+ try {
+ countDownLatch.await(100, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+ final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ assertThat(systemEGLDriver).isEqualTo("");
+
+ // Done with the test, remove the callback
+ SystemProperties.removeChangeCallback(countDown);
+ }
+
+ @Test
+ public void onDeveloperOptionSwitchDisabled_PreferenceShouldNotBeChecked() {
+ mController.onDeveloperOptionsSwitchDisabled();
+ assertThat(mPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void onDeveloperOptionSwitchDisabled_PreferenceShouldDisabled() {
+ mController.onDeveloperOptionsSwitchDisabled();
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void onRebootCancelled_ToggleSwitchFromOnToOff() {
+ // Add a callback when SystemProperty changes.
+ // This allows the thread to wait until
+ // GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ Runnable countDown = new Runnable() {
+ @Override
+ public void run() {
+ countDownLatch.countDown();
+ }
+ };
+ SystemProperties.addChangeCallback(countDown);
+
+ // Test that if the current persist.graphics.egl is "angle",
+ // when reboot is cancelled, persist.graphics.egl is changed back to "",
+ // and switch is set to unchecked.
+ when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
+ .thenReturn(ANGLE_DRIVER_SUFFIX);
+ mController.onRebootCancelled();
+ try {
+ countDownLatch.await(100, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+
+ final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ assertThat(systemEGLDriver).isEqualTo("");
+ assertThat(mPreference.isChecked()).isFalse();
+
+ // Done with the test, remove the callback.
+ SystemProperties.removeChangeCallback(countDown);
+ }
+
+ @Test
+ public void onRebootCancelled_ToggleSwitchFromOffToOn() {
+ // Add a callback when SystemProperty changes.
+ // This allows the thread to wait until
+ // GpuService::toggleAngleAsSystemDriver() updates the persist.graphics.egl.
+ final CountDownLatch countDownLatch = new CountDownLatch(1);
+ Runnable countDown = new Runnable() {
+ @Override
+ public void run() {
+ countDownLatch.countDown();
+ }
+ };
+ SystemProperties.addChangeCallback(countDown);
+
+ // Test that if the current persist.graphics.egl is "",
+ // when reboot is cancelled, persist.graphics.egl is changed back to "angle",
+ // and switch is set to checked.
+ when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
+ .thenReturn("");
+ mController.onRebootCancelled();
+ try {
+ countDownLatch.await(100, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+
+ final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
+ assertThat(systemEGLDriver).isEqualTo(ANGLE_DRIVER_SUFFIX);
+ assertThat(mPreference.isChecked()).isTrue();
+
+ // Done with the test, remove the callback.
+ SystemProperties.removeChangeCallback(countDown);
+ }
+
+}
diff --git a/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java b/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
index b0998c0..824954d 100644
--- a/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
+++ b/tests/unit/src/com/android/settings/localepicker/LocaleDialogFragmentTest.java
@@ -17,8 +17,8 @@
package com.android.settings.localepicker;
import static com.android.settings.localepicker.LocaleDialogFragment.ARG_DIALOG_TYPE;
-import static com.android.settings.localepicker.LocaleDialogFragment.ARG_RESULT_RECEIVER;
import static com.android.settings.localepicker.LocaleDialogFragment.ARG_TARGET_LOCALE;
+import static com.android.settings.localepicker.LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -27,12 +27,9 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
-import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
-import android.content.DialogInterface;
import android.os.Bundle;
-import android.os.ResultReceiver;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
@@ -55,6 +52,7 @@
public final MockitoRule mockito = MockitoJUnit.rule();
private Context mContext;
+ private LocaleListEditor mLocaleListEditor;
private LocaleDialogFragment mDialogFragment;
private FakeFeatureFactory mFeatureFactory;
@@ -62,30 +60,30 @@
public void setUp() throws Exception {
mContext = ApplicationProvider.getApplicationContext();
mDialogFragment = new LocaleDialogFragment();
+ mLocaleListEditor = spy(new LocaleListEditor());
mFeatureFactory = FakeFeatureFactory.setupForTest();
}
- private void setArgument(
- int type, ResultReceiver receiver) {
+ private void setArgument(int type) {
LocaleStore.LocaleInfo localeInfo = LocaleStore.getLocaleInfo(Locale.ENGLISH);
Bundle args = new Bundle();
args.putInt(ARG_DIALOG_TYPE, type);
args.putSerializable(ARG_TARGET_LOCALE, localeInfo);
- args.putParcelable(ARG_RESULT_RECEIVER, receiver);
mDialogFragment.setArguments(args);
}
@Test
public void getDialogContent_confirmSystemDefault_has2ButtonText() {
- setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null);
+ setArgument(DIALOG_CONFIRM_SYSTEM_DEFAULT);
LocaleDialogFragment.LocaleDialogController controller =
- new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+ mDialogFragment.getLocaleDialogController(mContext, mDialogFragment,
+ mLocaleListEditor);
LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
controller.getDialogContent();
assertEquals(ResourcesUtils.getResourcesString(
- mContext, "button_label_confirmation_of_system_locale_change"),
+ mContext, "button_label_confirmation_of_system_locale_change"),
dialogContent.mPositiveButton);
assertEquals(ResourcesUtils.getResourcesString(mContext, "cancel"),
dialogContent.mNegativeButton);
@@ -93,9 +91,10 @@
@Test
public void getDialogContent_unavailableLocale_has1ButtonText() {
- setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null);
+ setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE);
LocaleDialogFragment.LocaleDialogController controller =
- new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
+ mDialogFragment.getLocaleDialogController(mContext, mDialogFragment,
+ mLocaleListEditor);
LocaleDialogFragment.LocaleDialogController.DialogContent dialogContent =
controller.getDialogContent();
@@ -106,37 +105,8 @@
}
@Test
- public void onClick_clickPositiveButton_sendOK() {
- ResultReceiver resultReceiver = spy(new ResultReceiver(null));
- setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver);
- LocaleDialogFragment.LocaleDialogController controller =
- new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
-
- controller.onClick(null, DialogInterface.BUTTON_POSITIVE);
-
- verify(resultReceiver).send(eq(Activity.RESULT_OK), any());
- verify(mFeatureFactory.metricsFeatureProvider).action(
- mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE, true);
- }
-
- @Test
- public void onClick_clickNegativeButton_sendCancel() {
- ResultReceiver resultReceiver = spy(new ResultReceiver(null));
- setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, resultReceiver);
- LocaleDialogFragment.LocaleDialogController controller =
- new LocaleDialogFragment.LocaleDialogController(mContext, mDialogFragment);
-
- controller.onClick(null, DialogInterface.BUTTON_NEGATIVE);
-
- verify(resultReceiver).send(eq(Activity.RESULT_CANCELED), any());
- verify(mFeatureFactory.metricsFeatureProvider).action(
- mContext, SettingsEnums.ACTION_CHANGE_LANGUAGE, false);
- }
-
- @Test
public void getMetricsCategory_systemLocaleChange() {
- setArgument(LocaleDialogFragment.DIALOG_CONFIRM_SYSTEM_DEFAULT, null);
-
+ setArgument(DIALOG_CONFIRM_SYSTEM_DEFAULT);
int result = mDialogFragment.getMetricsCategory();
assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_CHANGE, result);
@@ -144,8 +114,7 @@
@Test
public void getMetricsCategory_unavailableLocale() {
- setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE, null);
-
+ setArgument(LocaleDialogFragment.DIALOG_NOT_AVAILABLE_LOCALE);
int result = mDialogFragment.getMetricsCategory();
assertEquals(SettingsEnums.DIALOG_SYSTEM_LOCALE_UNAVAILABLE, result);