getInstalledAccessibilityList(Context context) {
- final AccessibilityManager a11yManager = AccessibilityManager.getInstance(context);
+ /**
+ * Gets a list of {@link RestrictedPreference}s for the provided a11y shortcuts and services.
+ *
+ * {@code modifiableInstalledServiceList} may be modified to remove any entries with
+ * matching package name and label as an entry in {@code installedShortcutList}.
+ *
+ * @param installedShortcutList A list of installed {@link AccessibilityShortcutInfo}s.
+ * @param modifiableInstalledServiceList A modifiable list of installed
+ * {@link AccessibilityServiceInfo}s.
+ */
+ private List getInstalledAccessibilityPreferences(Context context,
+ List installedShortcutList,
+ List modifiableInstalledServiceList) {
final RestrictedPreferenceHelper preferenceHelper = new RestrictedPreferenceHelper(context);
- final List installedShortcutList =
- a11yManager.getInstalledAccessibilityShortcutListAsUser(context,
- UserHandle.myUserId());
final List activityList =
preferenceHelper.createAccessibilityActivityPreferenceList(installedShortcutList);
final Set> packageLabelPairs =
@@ -471,16 +491,14 @@ public class AccessibilitySettings extends DashboardFragment implements
a11yActivityPref.getPackageName(), a11yActivityPref.getLabel())
).collect(Collectors.toSet());
- // Remove duplicate item here, new a ArrayList to copy unmodifiable list result
- // (getInstalledAccessibilityServiceList).
- final List installedServiceList = new ArrayList<>(
- a11yManager.getInstalledAccessibilityServiceList());
+ // Remove duplicate A11yServices that are already shown as A11yActivities.
if (!packageLabelPairs.isEmpty()) {
- installedServiceList.removeIf(
+ modifiableInstalledServiceList.removeIf(
target -> containsPackageAndLabelInList(packageLabelPairs, target));
}
final List serviceList =
- preferenceHelper.createAccessibilityServicePreferenceList(installedServiceList);
+ preferenceHelper.createAccessibilityServicePreferenceList(
+ modifiableInstalledServiceList);
final List preferenceList = new ArrayList<>();
preferenceList.addAll(activityList);
@@ -489,6 +507,22 @@ public class AccessibilitySettings extends DashboardFragment implements
return preferenceList;
}
+ private static void removeNonPreinstalledComponents(
+ Map componentToCategory,
+ List shortcutInfos,
+ List serviceInfos) {
+ for (AccessibilityShortcutInfo info : shortcutInfos) {
+ if (!info.getActivityInfo().applicationInfo.isSystemApp()) {
+ componentToCategory.remove(info.getComponentName());
+ }
+ }
+ for (AccessibilityServiceInfo info : serviceInfos) {
+ if (!info.getResolveInfo().serviceInfo.applicationInfo.isSystemApp()) {
+ componentToCategory.remove(info.getComponentName());
+ }
+ }
+ }
+
private boolean containsPackageAndLabelInList(
Set> packageLabelPairs,
AccessibilityServiceInfo targetServiceInfo) {
diff --git a/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceController.java b/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceController.java
index 7dcd6612ac4..29971854e6b 100644
--- a/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceController.java
+++ b/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceController.java
@@ -17,26 +17,50 @@ package com.android.settings.accessibility;
import android.content.ContentResolver;
import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
import android.provider.Settings;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.DefaultLifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.server.accessibility.Flags;
+import com.android.settings.R;
import com.android.settings.core.SliderPreferenceController;
import com.android.settings.widget.SeekBarPreference;
/**
* The controller of the seekbar preference for the saturation level of color correction.
*/
-public class DaltonizerSaturationSeekbarPreferenceController extends SliderPreferenceController {
+public class DaltonizerSaturationSeekbarPreferenceController
+ extends SliderPreferenceController
+ implements DefaultLifecycleObserver {
private static final int DEFAULT_SATURATION_LEVEL = 7;
private static final int SATURATION_MAX = 10;
- private static final int SATURATION_MIN = 0;
+ private static final int SATURATION_MIN = 1;
private int mSliderPosition;
private final ContentResolver mContentResolver;
+ @Nullable
+ private SeekBarPreference mPreference;
+
+ public final ContentObserver mContentObserver = new ContentObserver(
+ new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange) {
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
+ }
+ };
+
public DaltonizerSaturationSeekbarPreferenceController(Context context,
String preferenceKey) {
super(context, preferenceKey);
@@ -49,10 +73,33 @@ public class DaltonizerSaturationSeekbarPreferenceController extends SliderPrefe
// TODO: Observer color correction on/off and enable/disable based on secure settings.
}
+ @Override
+ public void onStart(@NonNull LifecycleOwner owner) {
+ if (!isAvailable()) return;
+ mContentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER),
+ true,
+ mContentObserver
+ );
+ mContentResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED),
+ true,
+ mContentObserver
+ );
+ }
+
+ @Override
+ public void onStop(@NonNull LifecycleOwner owner) {
+ if (!isAvailable()) return;
+ mContentResolver.unregisterContentObserver(mContentObserver);
+ mPreference = null;
+ }
+
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
SeekBarPreference preference = screen.findPreference(getPreferenceKey());
+ mPreference = preference;
preference.setMax(getMax());
preference.setMin(getMin());
preference.setProgress(mSliderPosition);
@@ -62,7 +109,7 @@ public class DaltonizerSaturationSeekbarPreferenceController extends SliderPrefe
@Override
public int getAvailabilityStatus() {
if (Flags.enableColorCorrectionSaturation()) {
- return AVAILABLE;
+ return shouldSeekBarEnabled() ? AVAILABLE : DISABLED_DEPENDENT_SETTING;
}
return CONDITIONALLY_UNAVAILABLE;
}
@@ -85,6 +132,21 @@ public class DaltonizerSaturationSeekbarPreferenceController extends SliderPrefe
return true;
}
+ @Override
+ public void updateState(Preference preference) {
+ if (preference == null) {
+ return;
+ }
+
+ var shouldSeekbarEnabled = shouldSeekBarEnabled();
+ // setSummary not working yet on SeekBarPreference.
+ String summary = shouldSeekbarEnabled
+ ? ""
+ : mContext.getString(R.string.daltonizer_saturation_unavailable_summary);
+ preference.setSummary(summary);
+ preference.setEnabled(shouldSeekbarEnabled);
+ }
+
@Override
public int getMax() {
return SATURATION_MAX;
@@ -94,4 +156,16 @@ public class DaltonizerSaturationSeekbarPreferenceController extends SliderPrefe
public int getMin() {
return SATURATION_MIN;
}
+
+ private boolean shouldSeekBarEnabled() {
+ int enabled = Settings.Secure.getInt(
+ mContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0);
+ int mode = Settings.Secure.getInt(
+ mContentResolver, Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER, -1);
+
+ // enabled == 0 is disabled and also default.
+ // mode == 0 is gray scale where saturation level isn't applicable.
+ // mode == -1 is disabled and also default.
+ return enabled != 0 && mode != -1 && mode != 0;
+ }
}
diff --git a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
index b9a0b939a6b..835f3a87d68 100644
--- a/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
+++ b/src/com/android/settings/biometrics/combination/BiometricsSettingsBase.java
@@ -144,9 +144,10 @@ public abstract class BiometricsSettingsBase extends DashboardFragment {
launchChooseOrConfirmLock();
} else if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(
getActivity(), mBiometricsSuccessfullyAuthenticated,
- mBiometricsAuthenticationRequested)) {
+ mBiometricsAuthenticationRequested, mUserId)) {
mBiometricsAuthenticationRequested = true;
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+ Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+ mUserId);
}
updateUnlockPhonePreferenceSummary();
@@ -161,10 +162,11 @@ public abstract class BiometricsSettingsBase extends DashboardFragment {
public void onResume() {
super.onResume();
if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
- mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested)
+ mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested, mUserId)
&& mGkPwHandle != 0L) {
mBiometricsAuthenticationRequested = true;
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+ Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+ mUserId);
}
if (!mConfirmCredential) {
mDoNotFinishActivity = false;
diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java
index 2a0dd83a491..305d6703cfe 100644
--- a/src/com/android/settings/biometrics/face/FaceSettings.java
+++ b/src/com/android/settings/biometrics/face/FaceSettings.java
@@ -289,9 +289,11 @@ public class FaceSettings extends DashboardFragment {
finish();
}
} else if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
- mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested)) {
+ mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested,
+ mUserId)) {
mBiometricsAuthenticationRequested = true;
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+ Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+ mUserId);
} else {
mAttentionController.setToken(mToken);
mEnrollController.setToken(mToken);
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
index c4bbcdeea07..815c08e0de1 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java
@@ -485,9 +485,11 @@ public class FingerprintSettings extends SubSettings {
mLaunchedConfirm = true;
launchChooseOrConfirmLock();
} else if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
- mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested)) {
+ mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested,
+ mUserId)) {
mBiometricsAuthenticationRequested = true;
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+ Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+ mUserId);
} else if (!mHasFirstEnrolled) {
mIsEnrolling = true;
addFirstFingerprint(null);
@@ -777,9 +779,11 @@ public class FingerprintSettings extends SubSettings {
.getUdfpsEnrollCalibrator(getActivity().getApplicationContext(), null, null);
if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getActivity(),
- mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested)) {
+ mBiometricsSuccessfullyAuthenticated, mBiometricsAuthenticationRequested,
+ mUserId)) {
mBiometricsAuthenticationRequested = true;
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+ Utils.launchBiometricPromptForMandatoryBiometrics(this,
+ BIOMETRIC_AUTH_REQUEST, mUserId);
}
}
diff --git a/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt b/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
index 215692ab0e1..9bc920a96ba 100644
--- a/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
+++ b/src/com/android/settings/biometrics/fingerprint2/BiometricsEnvironment.kt
@@ -16,7 +16,9 @@
package com.android.settings.biometrics.fingerprint2
+import android.content.pm.PackageManager
import android.hardware.fingerprint.FingerprintManager
+import android.os.ServiceManager.ServiceNotFoundException
import android.view.MotionEvent
import android.view.accessibility.AccessibilityManager
import androidx.fragment.app.FragmentActivity
@@ -74,8 +76,15 @@ class BiometricsEnvironment(context: SettingsApplication) : ViewModelStoreOwner
private val backgroundDispatcher = executorService.asCoroutineDispatcher()
private val applicationScope = MainScope()
private val gateKeeperPasswordProvider = GatekeeperPasswordProvider(LockPatternUtils(context))
- private val fingerprintManager =
- context.getSystemService(FragmentActivity.FINGERPRINT_SERVICE) as FingerprintManager?
+ private val fingerprintManager = try {
+ if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ context.getSystemService(FragmentActivity.FINGERPRINT_SERVICE) as FingerprintManager?
+ } else {
+ null
+ }
+ } catch (exception: ServiceNotFoundException){
+ null
+ }
private val fingerprintSensorRepository: FingerprintSensorRepository =
FingerprintSensorRepositoryImpl(fingerprintManager, backgroundDispatcher, applicationScope)
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java
index bfccdc4c672..0a90e7b3c4a 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreference.java
@@ -92,6 +92,8 @@ public class AudioSharingNamePreference extends ValidatedEditTextPreference {
shareButton.setVisibility(View.VISIBLE);
shareButton.setImageDrawable(getContext().getDrawable(R.drawable.ic_qrcode_24dp));
shareButton.setOnClickListener(unused -> launchAudioSharingQrCodeFragment());
+ shareButton.setContentDescription(
+ getContext().getString(R.string.audio_sharing_qrcode_button_label));
}
private void configureInvisibleStateForQrCodeIcon(ImageButton shareButton, View divider) {
diff --git a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java
index e4c07949b41..47f9c75514e 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/audiostreams/AudioStreamsQrCodeFragment.java
@@ -55,7 +55,7 @@ public class AudioStreamsQrCodeFragment extends InstrumentedFragment {
@Override
public final View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- return inflater.inflate(R.xml.bluetooth_audio_streams_qr_code, container, false);
+ return inflater.inflate(R.layout.bluetooth_audio_streams_qr_code, container, false);
}
@Override
diff --git a/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java b/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java
index ff513c249f5..0d3d835dc5f 100644
--- a/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java
+++ b/src/com/android/settings/development/DesktopModeSecondaryDisplayPreferenceController.java
@@ -69,7 +69,8 @@ public class DesktopModeSecondaryDisplayPreferenceController extends
isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
if (isEnabled && mFragment != null) {
RebootConfirmationDialogFragment.show(
- mFragment, R.string.reboot_dialog_force_desktop_mode, this);
+ mFragment, R.string.reboot_dialog_enable_desktop_mode_on_secondary_display,
+ this);
}
return true;
}
diff --git a/src/com/android/settings/development/FreeformWindowsPreferenceController.java b/src/com/android/settings/development/FreeformWindowsPreferenceController.java
index 7cf7738f7b5..c02ffa7d00f 100644
--- a/src/com/android/settings/development/FreeformWindowsPreferenceController.java
+++ b/src/com/android/settings/development/FreeformWindowsPreferenceController.java
@@ -16,8 +16,9 @@
package com.android.settings.development;
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+
import android.content.Context;
-import android.os.Build;
import android.provider.Settings;
import androidx.annotation.Nullable;
@@ -40,7 +41,8 @@ public class FreeformWindowsPreferenceController extends DeveloperOptionsPrefere
@VisibleForTesting
static final int SETTING_VALUE_ON = 1;
- @Nullable private final DevelopmentSettingsDashboardFragment mFragment;
+ @Nullable
+ private final DevelopmentSettingsDashboardFragment mFragment;
public FreeformWindowsPreferenceController(
Context context, @Nullable DevelopmentSettingsDashboardFragment fragment) {
@@ -48,6 +50,13 @@ public class FreeformWindowsPreferenceController extends DeveloperOptionsPrefere
mFragment = fragment;
}
+ @Override
+ public boolean isAvailable() {
+ // When devices have the system feature FEATURE_FREEFORM_WINDOW_MANAGEMENT, freeform
+ // mode is enabled automatically, and this toggle is not needed.
+ return !mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+ }
+
@Override
public String getPreferenceKey() {
return ENABLE_FREEFORM_SUPPORT_KEY;
@@ -80,9 +89,4 @@ public class FreeformWindowsPreferenceController extends DeveloperOptionsPrefere
Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, SETTING_VALUE_OFF);
((TwoStatePreference) mPreference).setChecked(false);
}
-
- @VisibleForTesting
- String getBuildType() {
- return Build.TYPE;
- }
}
diff --git a/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceController.java b/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceController.java
index 23d4cc64efa..9f7512c45c9 100644
--- a/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceController.java
+++ b/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceController.java
@@ -30,85 +30,184 @@ import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+/**
+ * This preference represents the default log level for the Bluetooth stack
+ *
+ * The default log level is captured and held in an Android Log Framework log tag, using "bluetooth"
+ * as the tag name. The Log framework does not provide methods to directly write a log tag value,
+ * but instead leverages special system properties to hold the value of a log tag.
+ *
+ * This preferences aims to keep the selection in sync with the currently set log tag value. It
+ * writes directly to the system properties that hold the level associated with the bluetooth log
+ * tag. It leverages the Log.isLoggable("bluetooth", level) function to discern the current value.
+ * The default level is INFO.
+ *
+ * This value is read once at start of the Bluetooth stack. To use a new value once setting it, be
+ * sure to turn Bluetooth off and back on again.
+ */
public class BluetoothStackLogPreferenceController extends DeveloperOptionsPreferenceController
implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+ private static final String TAG = BluetoothStackLogPreferenceController.class.getSimpleName();
+
+ private static final String PREFERENCE_KEY = "bt_stack_log_level";
/* Ensure that the indexes match with bt_stack_log_values and bt_stack_log_entries ordering */
- private static final String PREFERENCE_KEY = "bt_stack_log_level";
- @VisibleForTesting static final int BTSTACK_LOG_MODE_VERBOSE_INDEX = 0;
- @VisibleForTesting static final int BTSTACK_LOG_MODE_DEBUG_INDEX = 1;
- @VisibleForTesting static final int BTSTACK_LOG_MODE_INFO_INDEX = 2;
- @VisibleForTesting static final int BTSTACK_LOG_MODE_WARN_INDEX = 3;
- @VisibleForTesting static final int BTSTACK_LOG_MODE_ERROR_INDEX = 4;
+ private static final int BT_LOG_LEVEL_VERBOSE_INDEX = 0;
+ private static final int BT_LOG_LEVEL_DEBUG_INDEX = 1;
+ private static final int BT_LOG_LEVEL_INFO_INDEX = 2;
+ private static final int BT_LOG_LEVEL_WARN_INDEX = 3;
+ private static final int BT_LOG_LEVEL_ERROR_INDEX = 4;
+ @VisibleForTesting static final int BT_LOG_LEVEL_DEFAULT_INDEX = BT_LOG_LEVEL_INFO_INDEX;
- @VisibleForTesting
- static final String BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST = "persist.log.tag.bluetooth";
- static final String BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY = "log.tag.bluetooth";
- static final String BLUETOOTH_STRING_NAME = "bluetooth";
- static final int DEFAULT_MODE = BTSTACK_LOG_MODE_INFO_INDEX;
-
- private final String[] mListValues;
- private final String[] mListEntries;
+ private static final String BT_LOG_TAG = "bluetooth";
+ @VisibleForTesting static final String BT_LOG_LEVEL_PROP_PERSIST = "persist.log.tag.bluetooth";
+ @VisibleForTesting static final String BT_LOG_LEVEL_PROP = "log.tag.bluetooth";
+ // Values represents the untranslatable log level strings that should be used for writing to
+ // system properties. Entries represents the translatable log level strings that should be used
+ // in the UI to communicate to the user their options for this preference.
+ private String[] mListValues;
+ private String[] mListEntries;
+ /**
+ * Create a BluetoothStackLogPreferenceController instance
+ */
public BluetoothStackLogPreferenceController(@NonNull Context context) {
super(context);
mListValues = context.getResources().getStringArray(R.array.bt_stack_log_level_values);
mListEntries = context.getResources().getStringArray(R.array.bt_stack_log_level_entries);
}
- /** returns default log level index of INFO */
- public int getDefaultModeIndex() {
- return DEFAULT_MODE;
- }
-
+ /**
+ * Returns the preference key associated with this preference
+ *
+ * Note that this key is _usually_ a system property in and of itself, which is expected to hold
+ * the value of the preference. In this case though, this key *does not* hold the preference. It
+ * is only really used to tie this controller to the list preference defined in the XML file.
+ *
+ * @return the preference key associated with this preference
+ */
@Override
@Nullable
public String getPreferenceKey() {
return PREFERENCE_KEY;
}
+ /**
+ * Update the state of the preference based on what the user has selected
+ *
+ * This function is invoked when the user has selected a new value for this preference. The new
+ * value is the entry value at the index of the list the user has selected. This value will be
+ * one of the values from the array returned in getEntryValues(). Specifically, this array is
+ * set using R.array.bt_stack_log_level_values
+ *
+ * @param preference - the preference object to set the value of
+ * @param newValue - the value the user has selected, as an Object
+ * @return True when updated successfully
+ */
@Override
public boolean onPreferenceChange(@NonNull Preference preference, @NonNull Object newValue) {
- SystemProperties.set(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST, newValue.toString());
- SystemProperties.set(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY, newValue.toString());
- updateState(mPreference);
+ Log.v(TAG, "onPreferenceChange(pref=" + preference + "value=" + newValue.toString() + ")");
+ setBluetoothLogTag(newValue.toString());
+ setBluetoothLogLevelIndex(getBluetoothLogLevelIndex());
return true;
}
+ /**
+ * Refresh the state of this preference based on the state stored on the system
+ *
+ * Read the Bluetooth stack log level from the underlying system property/log tag, and map that
+ * level to the proper index in the values and entries array. Use those strings to set the value
+ * and summary of the preference.
+ *
+ * @param preference - the preference object to refresh the state of
+ */
@Override
public void updateState(@NonNull Preference preference) {
- final ListPreference listPreference = (ListPreference) preference;
- int index = getBluetoothLogLevelIndex();
- listPreference.setValue(mListValues[index]);
- listPreference.setSummary(mListEntries[index]);
+ Log.v(TAG, "updateState(pref=" + preference + "): refresh preference state");
+ setBluetoothLogLevelIndex(getBluetoothLogLevelIndex());
}
/**
- * Returns the current log level from Log.isLoggable().
+ * Notify this developer options preference of a change to developer options visibility
+ *
+ * We developer options are closed, we should clear out the value of this developer option
+ * preference and revert it back to the default state of INFO.
*/
- @VisibleForTesting
- public int getBluetoothLogLevelIndex() {
- if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.VERBOSE)) {
- return BTSTACK_LOG_MODE_VERBOSE_INDEX;
- } else if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.DEBUG)) {
- return BTSTACK_LOG_MODE_DEBUG_INDEX;
- } else if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.INFO)) {
- return BTSTACK_LOG_MODE_INFO_INDEX;
- } else if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.WARN)) {
- return BTSTACK_LOG_MODE_WARN_INDEX;
- } else if (Log.isLoggable(BLUETOOTH_STRING_NAME, Log.ERROR)) {
- return BTSTACK_LOG_MODE_ERROR_INDEX;
- }
- return BTSTACK_LOG_MODE_INFO_INDEX;
- }
-
@Override
protected void onDeveloperOptionsSwitchDisabled() {
super.onDeveloperOptionsSwitchDisabled();
- SystemProperties.set(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST, null);
- SystemProperties.set(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY, null);
- ((ListPreference) mPreference).setValue(mListValues[getDefaultModeIndex()]);
- ((ListPreference) mPreference).setSummary(mListEntries[getDefaultModeIndex()]);
+ Log.v(TAG, "onDeveloperOptionsSwitchDisabled(): Revert stack log to default");
+ setBluetoothLogTag(null);
+ setBluetoothLogLevelIndex(BT_LOG_LEVEL_DEFAULT_INDEX);
+ }
+
+ /**
+ * Set the system property values used by the Log framework to read the "bluetooth" log tag
+ *
+ * @param logLevel - the log level to set the Bluetooth stack minimum log level to
+ */
+ private void setBluetoothLogTag(@Nullable String logLevel) {
+ Log.i(TAG, "setBluetoothLogTag(logLevel=" + logLevel + "): Set properties for log tag");
+ SystemProperties.set(BT_LOG_LEVEL_PROP_PERSIST, logLevel);
+ SystemProperties.set(BT_LOG_LEVEL_PROP, logLevel);
+ }
+
+ /**
+ * Get the entry and value index corresponding to the current Bluetooth stack log level
+ *
+ * Since this preference uses an actual log tag and not a specific/private system property, we
+ * can read the value using the Log.isLoggable() function with our "bluetooth" log tag that
+ * represents the log level of the Bluetooth stack. This is safer than trying to replacate the
+ * logic used in the Log framework around the various persist, ro, and blank variants of the tag
+ *
+ * If no value is present, INFO is used.
+ *
+ * @return the entry/value index corresponding to the current log level of the tag "bluetooth"
+ */
+ @VisibleForTesting
+ public int getBluetoothLogLevelIndex() {
+ int level = BT_LOG_LEVEL_DEFAULT_INDEX;
+ if (Log.isLoggable(BT_LOG_TAG, Log.VERBOSE)) {
+ level = BT_LOG_LEVEL_VERBOSE_INDEX;
+ } else if (Log.isLoggable(BT_LOG_TAG, Log.DEBUG)) {
+ level = BT_LOG_LEVEL_DEBUG_INDEX;
+ } else if (Log.isLoggable(BT_LOG_TAG, Log.INFO)) {
+ level = BT_LOG_LEVEL_INFO_INDEX;
+ } else if (Log.isLoggable(BT_LOG_TAG, Log.WARN)) {
+ level = BT_LOG_LEVEL_WARN_INDEX;
+ } else if (Log.isLoggable(BT_LOG_TAG, Log.ERROR)) {
+ level = BT_LOG_LEVEL_ERROR_INDEX;
+ }
+ Log.v(TAG, "getBluetoothLogLevelIndex() -> " + level);
+ return level;
+ }
+
+ /**
+ * Set the current Bluetooth stack log level displayed in the list for this preference
+ *
+ * @param index - the index representing the log level choice of this preference
+ */
+ private void setBluetoothLogLevelIndex(int index) {
+ if (index < BT_LOG_LEVEL_VERBOSE_INDEX || index > BT_LOG_LEVEL_ERROR_INDEX) {
+ Log.e(TAG, "setBluetoothLogLevelIndex(index=" + index + "): Log level invalid");
+ return;
+ }
+
+ String value = mListValues[index];
+ String entryValue = mListEntries[index];
+
+ ListPreference preference = ((ListPreference) mPreference);
+ if (preference == null) {
+ Log.e(TAG, "setBluetoothLogLevelIndex(index=" + index + "): mPreference is null");
+ return;
+ }
+
+ preference.setValue(value);
+ preference.setSummary(entryValue);
+
+ Log.i(TAG, "setBluetoothLogLevelIndex(index=" + index
+ + "): Updated Bluetooth stack log level to value='" + value + "', entryValue='"
+ + entryValue + "'");
}
}
diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
index 7d15858f8b5..f121d0c2e5b 100644
--- a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
@@ -81,7 +81,10 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
return mContext.getString(
com.android.settingslib.R.string.battery_info_status_not_charging);
}
- if (BatteryUtils.isBatteryDefenderOn(info)) {
+ if (BatteryUtils.isBatteryDefenderOn(info)
+ || FeatureFactory.getFeatureFactory()
+ .getPowerUsageFeatureProvider()
+ .isExtraDefend()) {
return mContext.getString(
com.android.settingslib.R.string.battery_info_status_charging_on_hold);
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
index bfa501c16aa..f710c71c969 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiver.java
@@ -63,8 +63,8 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver {
}
final String action = intent.getAction();
Log.d(TAG, "onReceive:" + action);
- if (com.android.settingslib.fuelgauge.BatteryUtils.isWorkProfile(context)) {
- Log.w(TAG, "do nothing for work profile action=" + action);
+ if (com.android.settingslib.fuelgauge.BatteryUtils.isAdditionalProfile(context)) {
+ Log.w(TAG, "do nothing for an additional profile action=" + action);
return;
}
DatabaseUtils.recordDateTime(context, action);
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
index 095a65a8e10..52010afc77b 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProvider.java
@@ -110,8 +110,8 @@ public class BatteryUsageContentProvider extends ContentProvider {
@Override
public boolean onCreate() {
- if (BatteryUtils.isWorkProfile(getContext())) {
- Log.w(TAG, "do not create provider for work profile");
+ if (BatteryUtils.isAdditionalProfile(getContext())) {
+ Log.w(TAG, "do not create provider for an additional profile");
return false;
}
mClock = Clock.systemUTC();
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
index b758df4bd6b..45d724fb208 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java
@@ -54,8 +54,8 @@ public final class BootBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent == null ? "" : intent.getAction();
- if (BatteryUtils.isWorkProfile(context)) {
- Log.w(TAG, "do not start job for work profile action=" + action);
+ if (BatteryUtils.isAdditionalProfile(context)) {
+ Log.w(TAG, "do not start job for an additional profile action=" + action);
return;
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
index 76203232329..6feb815dc13 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtils.java
@@ -70,6 +70,7 @@ public final class DatabaseUtils {
/** Clear memory threshold for device booting phase. */
private static final long CLEAR_MEMORY_THRESHOLD_MS = Duration.ofMinutes(5).toMillis();
+
private static final long CLEAR_MEMORY_DELAYED_MS = Duration.ofSeconds(2).toMillis();
private static final long INVALID_TIMESTAMP = 0L;
@@ -527,9 +528,11 @@ public final class DatabaseUtils {
return startCalendar.getTimeInMillis();
}
- /** Returns the context with profile parent identity when current user is work profile. */
+ /**
+ * Returns the context with profile parent identity when current user is an additional profile.
+ */
public static Context getParentContext(Context context) {
- if (com.android.settingslib.fuelgauge.BatteryUtils.isWorkProfile(context)) {
+ if (com.android.settingslib.fuelgauge.BatteryUtils.isAdditionalProfile(context)) {
try {
return context.createPackageContextAsUser(
/* packageName= */ context.getPackageName(),
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
index 5c73adb69f9..982cf406101 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java
@@ -50,10 +50,10 @@ public final class PeriodicJobReceiver extends BroadcastReceiver {
Log.w(TAG, "receive unexpected action=" + action);
return;
}
- if (BatteryUtils.isWorkProfile(context)) {
+ if (BatteryUtils.isAdditionalProfile(context)) {
BatteryUsageLogUtils.writeLog(
- context, Action.SCHEDULE_JOB, "do not refresh job for work profile");
- Log.w(TAG, "do not refresh job for work profile action=" + action);
+ context, Action.SCHEDULE_JOB, "do not refresh job for an additional profile");
+ Log.w(TAG, "do not refresh job for an additional profile action=" + action);
return;
}
BatteryUsageLogUtils.writeLog(context, Action.EXECUTE_JOB, "");
diff --git a/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
index 7e759ee3f26..e829a3cd98c 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java
@@ -49,8 +49,8 @@ public final class BugReportContentProvider extends ContentProvider {
Log.w(TAG, "failed to dump BatteryUsage state: null application context");
return;
}
- if (BatteryUtils.isWorkProfile(context)) {
- Log.w(TAG, "ignore battery usage states dump in the work profile");
+ if (BatteryUtils.isAdditionalProfile(context)) {
+ Log.w(TAG, "ignore battery usage states dump in the additional profile");
return;
}
writer.println("dump BatteryUsage and AppUsage states:");
diff --git a/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java
index 86135a96190..1f979022670 100644
--- a/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceController.java
@@ -16,14 +16,26 @@
package com.android.settings.notification.modes;
+import static android.app.AutomaticZenRule.TYPE_BEDTIME;
+import static android.app.AutomaticZenRule.TYPE_DRIVING;
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
+import static android.service.notification.ZenModeConfig.tryParseScheduleConditionId;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.service.notification.SystemZenRules;
+import android.service.notification.ZenModeConfig;
import android.util.Log;
+import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
+import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
@@ -35,6 +47,8 @@ import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;
+import com.google.common.base.Strings;
+
/**
* Preference controller for the link to an individual mode's configuration page.
*/
@@ -42,26 +56,29 @@ class ZenModeSetTriggerLinkPreferenceController extends AbstractZenModePreferenc
private static final String TAG = "ZenModeSetTriggerLink";
@VisibleForTesting
- protected static final String AUTOMATIC_TRIGGER_PREF_KEY = "zen_automatic_trigger_settings";
+ static final String AUTOMATIC_TRIGGER_KEY = "zen_automatic_trigger_settings";
+ static final String ADD_TRIGGER_KEY = "zen_add_automatic_trigger";
+ private final DashboardFragment mFragment;
+ private final PackageManager mPackageManager;
private final ConfigurationActivityHelper mConfigurationActivityHelper;
private final ZenServiceListing mServiceListing;
- private final DashboardFragment mFragment;
ZenModeSetTriggerLinkPreferenceController(Context context, String key,
DashboardFragment fragment, ZenModesBackend backend) {
- this(context, key, fragment, backend,
+ this(context, key, fragment, backend, context.getPackageManager(),
new ConfigurationActivityHelper(context.getPackageManager()),
new ZenServiceListing(context));
}
@VisibleForTesting
ZenModeSetTriggerLinkPreferenceController(Context context, String key,
- DashboardFragment fragment, ZenModesBackend backend,
+ DashboardFragment fragment, ZenModesBackend backend, PackageManager packageManager,
ConfigurationActivityHelper configurationActivityHelper,
ZenServiceListing serviceListing) {
super(context, key, backend);
mFragment = fragment;
+ mPackageManager = packageManager;
mConfigurationActivityHelper = configurationActivityHelper;
mServiceListing = serviceListing;
}
@@ -83,64 +100,137 @@ class ZenModeSetTriggerLinkPreferenceController extends AbstractZenModePreferenc
// This controller is expected to govern a preference category so that it controls the
// availability of the entire preference category if the mode doesn't have a way to
// automatically trigger (such as manual DND).
- PrimarySwitchPreference switchPref = ((PreferenceCategory) preference).findPreference(
- AUTOMATIC_TRIGGER_PREF_KEY);
- if (switchPref == null) {
+ if (zenMode.isManualDnd()) {
return;
}
- switchPref.setChecked(zenMode.getRule().isEnabled());
- switchPref.setOnPreferenceChangeListener(mSwitchChangeListener);
- switchPref.setSummary(zenMode.getRule().getTriggerDescription());
- switchPref.setIcon(null);
- switchPref.setOnPreferenceClickListener(null);
- switchPref.setIntent(null);
+ PrimarySwitchPreference triggerPref = checkNotNull(
+ ((PreferenceCategory) preference).findPreference(AUTOMATIC_TRIGGER_KEY));
+ Preference addTriggerPref = checkNotNull(
+ ((PreferenceCategory) preference).findPreference(ADD_TRIGGER_KEY));
- if (zenMode.isSystemOwned()) {
- if (zenMode.getType() == TYPE_SCHEDULE_TIME) {
- switchPref.setTitle(R.string.zen_mode_set_schedule_link);
- // TODO: b/332937635 - set correct metrics category
- switchPref.setIntent(ZenSubSettingLauncher.forModeFragment(mContext,
- ZenModeSetScheduleFragment.class, zenMode.getId(), 0).toIntent());
- } else if (zenMode.getType() == TYPE_SCHEDULE_CALENDAR) {
- switchPref.setTitle(R.string.zen_mode_set_calendar_link);
- switchPref.setIcon(null);
- // TODO: b/332937635 - set correct metrics category
- switchPref.setIntent(ZenSubSettingLauncher.forModeFragment(mContext,
- ZenModeSetCalendarFragment.class, zenMode.getId(), 0).toIntent());
- } else {
- switchPref.setTitle(R.string.zen_mode_select_schedule);
- switchPref.setIcon(R.drawable.ic_add_24dp);
- switchPref.setSummary("");
- // TODO: b/342156843 - Hide the switch (needs support in SettingsLib).
- switchPref.setOnPreferenceClickListener(clickedPreference -> {
- ZenModeScheduleChooserDialog.show(mFragment, mOnScheduleOptionListener);
- return true;
- });
- }
+ boolean isAddTrigger = zenMode.isSystemOwned() && zenMode.getType() != TYPE_SCHEDULE_TIME
+ && zenMode.getType() != TYPE_SCHEDULE_CALENDAR;
+
+ if (isAddTrigger) {
+ triggerPref.setVisible(false);
+ addTriggerPref.setVisible(true);
+ addTriggerPref.setOnPreferenceClickListener(unused -> {
+ ZenModeScheduleChooserDialog.show(mFragment, mOnScheduleOptionListener);
+ return true;
+ });
} else {
- Intent intent = mConfigurationActivityHelper.getConfigurationActivityIntentForMode(
- zenMode, mServiceListing::findService);
- if (intent != null) {
- preference.setVisible(true);
- switchPref.setTitle(R.string.zen_mode_configuration_link_title);
- switchPref.setSummary(zenMode.getRule().getTriggerDescription());
- switchPref.setIntent(intent);
+ addTriggerPref.setVisible(false);
+ triggerPref.setVisible(true);
+ triggerPref.setChecked(zenMode.getRule().isEnabled());
+ triggerPref.setOnPreferenceChangeListener(mSwitchChangeListener);
+
+ if (zenMode.isSystemOwned()) {
+ setUpForSystemOwnedTrigger(triggerPref, zenMode);
} else {
- Log.i(TAG, "No intent found for " + zenMode.getRule().getName());
- preference.setVisible(false);
+ setUpForAppTrigger(triggerPref, zenMode);
}
}
}
+ private void setUpForSystemOwnedTrigger(Preference preference, ZenMode mode) {
+ if (mode.getType() == TYPE_SCHEDULE_TIME) {
+ // TODO: b/332937635 - set correct metrics category
+ preference.setIntent(ZenSubSettingLauncher.forModeFragment(mContext,
+ ZenModeSetScheduleFragment.class, mode.getId(), 0).toIntent());
+
+ // [Clock Icon] 9:00 - 17:00 / Sun-Mon
+ preference.setIcon(com.android.internal.R.drawable.ic_zen_mode_type_schedule_time);
+ ZenModeConfig.ScheduleInfo schedule =
+ tryParseScheduleConditionId(mode.getRule().getConditionId());
+ if (schedule != null) {
+ preference.setTitle(SystemZenRules.getTimeSummary(mContext, schedule));
+ preference.setSummary(SystemZenRules.getShortDaysSummary(mContext, schedule));
+ } else {
+ // Fallback, but shouldn't happen.
+ Log.wtf(TAG, "SCHEDULE_TIME mode without schedule: " + mode);
+ preference.setTitle(R.string.zen_mode_set_schedule_link);
+ preference.setSummary(null);
+ }
+ } else if (mode.getType() == TYPE_SCHEDULE_CALENDAR) {
+ // TODO: b/332937635 - set correct metrics category
+ preference.setIntent(ZenSubSettingLauncher.forModeFragment(mContext,
+ ZenModeSetCalendarFragment.class, mode.getId(), 0).toIntent());
+
+ // [Event Icon] Calendar Events /
+ preference.setIcon(
+ com.android.internal.R.drawable.ic_zen_mode_type_schedule_calendar);
+ preference.setTitle(R.string.zen_mode_trigger_title_schedule_calendar);
+ preference.setSummary(mode.getTriggerDescription());
+ } else {
+ Log.wtf(TAG, "Unexpected type for system-owned mode: " + mode);
+ }
+ }
+
+ @SuppressLint("SwitchIntDef")
+ private void setUpForAppTrigger(Preference preference, ZenMode mode) {
+ // App-owned mode may have triggerDescription, configurationActivity, or both/neither.
+ Intent configurationIntent =
+ mConfigurationActivityHelper.getConfigurationActivityIntentForMode(
+ mode, mServiceListing::findService);
+
+ @StringRes int title = switch (mode.getType()) {
+ case TYPE_BEDTIME -> R.string.zen_mode_trigger_title_bedtime;
+ case TYPE_DRIVING -> R.string.zen_mode_trigger_title_driving;
+ default -> R.string.zen_mode_trigger_title_generic;
+ };
+
+ String summary;
+ if (!Strings.isNullOrEmpty(mode.getTriggerDescription())) {
+ summary = mode.getTriggerDescription();
+ } else if (!Strings.isNullOrEmpty(mode.getRule().getPackageName())) {
+ String appName = null;
+ try {
+ ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
+ mode.getRule().getPackageName(), 0);
+ appName = appInfo.loadLabel(mPackageManager).toString();
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Couldn't resolve owner for mode: " + mode);
+ }
+
+ if (appName != null) {
+ summary = mContext.getString(
+ configurationIntent != null
+ ? R.string.zen_mode_trigger_summary_settings_in_app
+ : R.string.zen_mode_trigger_summary_managed_by_app,
+ appName);
+ } else {
+ summary = null;
+ }
+ } else {
+ Log.e(TAG, "Mode without package! " + mode);
+ summary = null;
+ }
+
+ @DrawableRes int icon;
+ if (mode.getType() == TYPE_BEDTIME) {
+ icon = com.android.internal.R.drawable.ic_zen_mode_type_schedule_time; // Clock
+ } else if (mode.getType() == TYPE_DRIVING) {
+ icon = com.android.internal.R.drawable.ic_zen_mode_type_driving; // Car
+ } else {
+ icon = configurationIntent != null ? R.drawable.ic_zen_mode_trigger_with_activity
+ : R.drawable.ic_zen_mode_trigger_without_activity;
+ }
+
+ preference.setTitle(title);
+ preference.setSummary(summary);
+ preference.setIcon(icon);
+ preference.setIntent(configurationIntent);
+ }
+
@VisibleForTesting
final ZenModeScheduleChooserDialog.OnScheduleOptionListener mOnScheduleOptionListener =
conditionId -> saveMode(mode -> {
mode.setCustomModeConditionId(mContext, conditionId);
return mode;
+ // TODO: b/342156843 - Maybe jump to the corresponding schedule editing screen?
});
- @VisibleForTesting
- protected Preference.OnPreferenceChangeListener mSwitchChangeListener = (p, newValue) -> {
+ private final Preference.OnPreferenceChangeListener mSwitchChangeListener = (p, newValue) -> {
final boolean newEnabled = (Boolean) newValue;
return saveMode((zenMode) -> {
if (newEnabled != zenMode.getRule().isEnabled()) {
@@ -148,6 +238,5 @@ class ZenModeSetTriggerLinkPreferenceController extends AbstractZenModePreferenc
}
return zenMode;
});
- // TODO: b/342156843 - Do we want to jump to the corresponding schedule editing screen?
};
}
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index b4f13e8d77b..d5d079ecf6d 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -492,9 +492,10 @@ public class ChooseLockGeneric extends SettingsActivity {
: null;
updatePreferencesOrFinish(false /* isRecreatingActivity */);
if (Utils.requestBiometricAuthenticationForMandatoryBiometrics(getContext(),
- mBiometricsAuthSuccessful, mWaitingForConfirmation)) {
+ mBiometricsAuthSuccessful, mWaitingForConfirmation, mUserId)) {
mWaitingForConfirmation = true;
- Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST);
+ Utils.launchBiometricPromptForMandatoryBiometrics(this, BIOMETRIC_AUTH_REQUEST,
+ mUserId);
}
} else if (requestCode == BIOMETRIC_AUTH_REQUEST) {
if (resultCode == Activity.RESULT_OK) {
diff --git a/tests/robotests/src/com/android/settings/MainClearTest.java b/tests/robotests/src/com/android/settings/MainClearTest.java
index 187fce113f9..26a430b161c 100644
--- a/tests/robotests/src/com/android/settings/MainClearTest.java
+++ b/tests/robotests/src/com/android/settings/MainClearTest.java
@@ -140,8 +140,8 @@ public class MainClearTest {
when(mScrollView.getChildCount()).thenReturn(1);
doReturn(mMockActivity).when(mMainClear).getActivity();
when(mMockActivity.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
- when(mBiometricManager.canAuthenticate(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ when(mBiometricManager.canAuthenticate(anyInt(),
+ eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
}
@@ -370,8 +370,8 @@ public class MainClearTest {
when(mContext.getResources()).thenReturn(mResources);
when(mMockActivity.getSystemService(BiometricManager.class)).thenReturn(mBiometricManager);
when(mResources.getString(anyInt())).thenReturn(TEST_ACCOUNT_NAME);
- when(mBiometricManager.canAuthenticate(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ when(mBiometricManager.canAuthenticate(anyInt(),
+ eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
doReturn(true).when(mMainClear).isValidRequestCode(eq(MainClear.KEYGUARD_REQUEST));
doNothing().when(mMainClear).startActivityForResult(any(), anyInt());
diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java
index fd97b78d2ec..b36e9d63e32 100644
--- a/tests/robotests/src/com/android/settings/UtilsTest.java
+++ b/tests/robotests/src/com/android/settings/UtilsTest.java
@@ -81,6 +81,7 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.password.ConfirmDeviceCredentialActivity;
import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
@@ -532,31 +533,45 @@ public class UtilsTest {
when(mContext.getSystemService(BiometricManager.class)).thenReturn(null);
assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
false /* biometricsSuccessfullyAuthenticated */,
- false /* biometricsAuthenticationRequested */)).isFalse();
+ false /* biometricsAuthenticationRequested */, USER_ID)).isFalse();
}
@Test
@EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
public void testRequestBiometricAuthentication_biometricManagerReturnsSuccess_shouldReturnTrue() {
- when(mBiometricManager.canAuthenticate(
+ when(mBiometricManager.canAuthenticate(USER_ID,
BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
- boolean requestBiometricAuthenticationForMandatoryBiometrics =
+ final boolean requestBiometricAuthenticationForMandatoryBiometrics =
Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
- true /* biometricsSuccessfullyAuthenticated */,
- false /* biometricsAuthenticationRequested */);
- assertThat(requestBiometricAuthenticationForMandatoryBiometrics).isFalse();
+ false /* biometricsSuccessfullyAuthenticated */,
+ false /* biometricsAuthenticationRequested */, USER_ID);
+ assertThat(requestBiometricAuthenticationForMandatoryBiometrics).isTrue();
}
@Test
@EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
public void testRequestBiometricAuthentication_biometricManagerReturnsError_shouldReturnFalse() {
- when(mBiometricManager.canAuthenticate(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ when(mBiometricManager.canAuthenticate(anyInt(),
+ eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
false /* biometricsSuccessfullyAuthenticated */,
- false /* biometricsAuthenticationRequested */)).isFalse();
+ false /* biometricsAuthenticationRequested */, USER_ID)).isFalse();
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MANDATORY_BIOMETRICS)
+ public void testRequestBiometricAuthentication_biometricManagerReturnsSuccessForDifferentUser_shouldReturnFalse() {
+ when(mBiometricManager.canAuthenticate(anyInt(),
+ eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
+ .thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
+ when(mBiometricManager.canAuthenticate(0 /* userId */,
+ BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ .thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
+ assertThat(Utils.requestBiometricAuthenticationForMandatoryBiometrics(mContext,
+ false /* biometricsSuccessfullyAuthenticated */,
+ false /* biometricsAuthenticationRequested */, USER_ID)).isFalse();
}
@Test
@@ -566,7 +581,7 @@ public class UtilsTest {
final int requestCode = 1;
final ArgumentCaptor intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
- Utils.launchBiometricPromptForMandatoryBiometrics(mFragment, requestCode);
+ Utils.launchBiometricPromptForMandatoryBiometrics(mFragment, requestCode, USER_ID);
verify(mFragment).startActivityForResult(intentArgumentCaptor.capture(), eq(requestCode));
@@ -576,9 +591,12 @@ public class UtilsTest {
BiometricManager.Authenticators.MANDATORY_BIOMETRICS);
assertThat(intent.getExtra(BIOMETRIC_PROMPT_NEGATIVE_BUTTON_TEXT)).isNotNull();
assertThat(intent.getExtra(KeyguardManager.EXTRA_DESCRIPTION)).isNotNull();
+ assertThat(intent.getBooleanExtra(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, false))
+ .isTrue();
+ assertThat(intent.getIntExtra(Intent.EXTRA_USER_ID, 0)).isEqualTo(USER_ID);
assertThat(intent.getComponent().getPackageName()).isEqualTo(SETTINGS_PACKAGE_NAME);
assertThat(intent.getComponent().getClassName()).isEqualTo(
- ConfirmDeviceCredentialActivity.class.getName());
+ ConfirmDeviceCredentialActivity.InternalActivity.class.getName());
}
private void setUpForConfirmCredentialString(boolean isEffectiveUserManagedProfile) {
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
index 1463cd0b7f9..cb2429c558f 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
@@ -26,11 +26,9 @@ import static org.robolectric.Shadows.shadowOf;
import static java.util.Collections.singletonList;
import android.accessibilityservice.AccessibilityServiceInfo;
-import android.accessibilityservice.AccessibilityShortcutInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -110,9 +108,7 @@ public class AccessibilitySettingsTest {
private final Context mContext = ApplicationProvider.getApplicationContext();
@Spy
private final AccessibilityServiceInfo mServiceInfo = getMockAccessibilityServiceInfo(
- PACKAGE_NAME, CLASS_NAME);
- @Mock
- private AccessibilityShortcutInfo mShortcutInfo;
+ new ComponentName(PACKAGE_NAME, CLASS_NAME));
private ShadowAccessibilityManager mShadowAccessibilityManager;
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
@@ -125,7 +121,6 @@ public class AccessibilitySettingsTest {
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(new ArrayList<>());
mContext.setTheme(androidx.appcompat.R.style.Theme_AppCompat);
ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager;
- setMockAccessibilityShortcutInfo(mShortcutInfo);
Intent intent = new Intent();
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT,
@@ -398,14 +393,25 @@ public class AccessibilitySettingsTest {
public void testAccessibilityMenuInSystem_IncludedInInteractionControl() {
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
List.of(getMockAccessibilityServiceInfo(
- AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM)));
+ AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM,
+ /*isSystemApp=*/true)));
setupFragment();
- final RestrictedPreference pref = mFragment.getPreferenceScreen().findPreference(
- AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM.flattenToString());
- final String prefCategory = mFragment.mServicePreferenceToPreferenceCategoryMap.get(
- pref).getKey();
- assertThat(prefCategory).isEqualTo(AccessibilitySettings.CATEGORY_INTERACTION_CONTROL);
+ assertThat(getPreferenceCategory(AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM))
+ .isEqualTo(AccessibilitySettings.CATEGORY_INTERACTION_CONTROL);
+ }
+
+ @Test
+ @EnableFlags(com.android.settings.accessibility.Flags.FLAG_CHECK_PREBUNDLED_IS_PREINSTALLED)
+ public void testNonPreinstalledApp_IncludedInDownloadedCategory() {
+ mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
+ List.of(getMockAccessibilityServiceInfo(
+ AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM,
+ /*isSystemApp=*/false)));
+ setupFragment();
+
+ assertThat(getPreferenceCategory(AccessibilityUtils.ACCESSIBILITY_MENU_IN_SYSTEM))
+ .isEqualTo(AccessibilitySettings.CATEGORY_DOWNLOADED_SERVICES);
}
@Test
@@ -418,13 +424,20 @@ public class AccessibilitySettingsTest {
assertThat(pref).isNull();
}
- private AccessibilityServiceInfo getMockAccessibilityServiceInfo(String packageName,
- String className) {
- return getMockAccessibilityServiceInfo(new ComponentName(packageName, className));
+ private String getPreferenceCategory(ComponentName componentName) {
+ return mFragment.mServicePreferenceToPreferenceCategoryMap.get(
+ mFragment.getPreferenceScreen().findPreference(
+ componentName.flattenToString())).getKey();
}
private AccessibilityServiceInfo getMockAccessibilityServiceInfo(ComponentName componentName) {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
+ return getMockAccessibilityServiceInfo(componentName, true);
+ }
+
+ private AccessibilityServiceInfo getMockAccessibilityServiceInfo(ComponentName componentName,
+ boolean isSystemApp) {
+ final ApplicationInfo applicationInfo = Mockito.mock(ApplicationInfo.class);
+ when(applicationInfo.isSystemApp()).thenReturn(isSystemApp);
final ServiceInfo serviceInfo = new ServiceInfo();
applicationInfo.packageName = componentName.getPackageName();
serviceInfo.packageName = componentName.getPackageName();
@@ -445,16 +458,6 @@ public class AccessibilitySettingsTest {
return null;
}
- private void setMockAccessibilityShortcutInfo(AccessibilityShortcutInfo mockInfo) {
- final ActivityInfo activityInfo = Mockito.mock(ActivityInfo.class);
- activityInfo.applicationInfo = new ApplicationInfo();
- when(mockInfo.getActivityInfo()).thenReturn(activityInfo);
- when(activityInfo.loadLabel(any())).thenReturn(DEFAULT_LABEL);
- when(mockInfo.loadSummary(any())).thenReturn(DEFAULT_SUMMARY);
- when(mockInfo.loadDescription(any())).thenReturn(DEFAULT_DESCRIPTION);
- when(mockInfo.getComponentName()).thenReturn(COMPONENT_NAME);
- }
-
private void setInvisibleToggleFragmentType(AccessibilityServiceInfo info) {
info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion = Build.VERSION_CODES.R;
info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
diff --git a/tests/robotests/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceControllerTest.java
index 98ed4422dc8..5fd11f910fa 100644
--- a/tests/robotests/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/DaltonizerSaturationSeekbarPreferenceControllerTest.java
@@ -16,38 +16,39 @@
package com.android.settings.accessibility;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
import android.content.ContentResolver;
import android.content.Context;
+import android.os.Looper;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
+import androidx.lifecycle.LifecycleOwner;
+import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.server.accessibility.Flags;
import com.android.settings.widget.SeekBarPreference;
+import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
/** Tests for {@link DaltonizerSaturationSeekbarPreferenceController}. */
@@ -60,8 +61,9 @@ public class DaltonizerSaturationSeekbarPreferenceControllerTest {
private int mOriginalSaturationLevel = -1;
private PreferenceScreen mScreen;
+ private LifecycleOwner mLifecycleOwner;
+ private Lifecycle mLifecycle;
- @Mock
private SeekBarPreference mPreference;
@Rule
@@ -69,7 +71,6 @@ public class DaltonizerSaturationSeekbarPreferenceControllerTest {
@Before
public void setup() {
- MockitoAnnotations.initMocks(this);
Context context = ApplicationProvider.getApplicationContext();
mContentResolver = context.getContentResolver();
mOriginalSaturationLevel = Settings.Secure.getInt(
@@ -77,10 +78,13 @@ public class DaltonizerSaturationSeekbarPreferenceControllerTest {
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
7);
- mScreen = spy(new PreferenceScreen(context, /* attrs= */ null));
- when(mScreen.findPreference(ToggleDaltonizerPreferenceFragment.KEY_SATURATION))
- .thenReturn(mPreference);
+ mPreference = new SeekBarPreference(context);
+ mPreference.setKey(ToggleDaltonizerPreferenceFragment.KEY_SATURATION);
+ mScreen = new PreferenceManager(context).createPreferenceScreen(context);
+ mScreen.addPreference(mPreference);
+ mLifecycleOwner = () -> mLifecycle;
+ mLifecycle = new Lifecycle(mLifecycleOwner);
mController = new DaltonizerSaturationSeekbarPreferenceController(
context,
ToggleDaltonizerPreferenceFragment.KEY_SATURATION);
@@ -94,6 +98,12 @@ public class DaltonizerSaturationSeekbarPreferenceControllerTest {
mOriginalSaturationLevel);
}
+ @Test
+ public void constructor_defaultValuesMatch() {
+ assertThat(mController.getSliderPosition()).isEqualTo(7);
+ assertThat(mController.getMax()).isEqualTo(10);
+ assertThat(mController.getMin()).isEqualTo(1);
+ }
@Test
@DisableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
@@ -103,28 +113,72 @@ public class DaltonizerSaturationSeekbarPreferenceControllerTest {
@Test
@EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
- public void getAvailabilityStatus_flagEnabled_available() {
+ public void getAvailabilityStatus_flagEnabledProtanEnabled_available() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
- public void constructor_defaultValuesMatch() {
- assertThat(mController.getSliderPosition()).isEqualTo(7);
- assertThat(mController.getMax()).isEqualTo(10);
- assertThat(mController.getMin()).isEqualTo(0);
+ @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+ public void getAvailabilityStatus_flagEnabledDeutranEnabled_available() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 12);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
@EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
- public void displayPreference_enabled_visible() {
+ public void getAvailabilityStatus_flagEnabledTritanEnabled_available() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 13);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+ public void getAvailabilityStatus_flagEnabledGrayScale_disabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 0);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+ public void getAvailabilityStatus_flagEnabledColorCorrectionDisabled_disabled() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 11);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+ public void getAvailabilityStatus_flagEnabledColorCorrectionDisabledGrayScale_disabled() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 0);
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+ public void displayPreference_flagEnabledColorCorrectionEnabled_enabledWithDefaultValues() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
mController.displayPreference(mScreen);
- verify(mPreference).setMax(eq(10));
- verify(mPreference).setMin(eq(0));
- verify(mPreference).setProgress(eq(7));
- verify(mPreference).setContinuousUpdates(eq(true));
- verify(mPreference).setOnPreferenceChangeListener(eq(mController));
- verify(mPreference).setVisible(eq(true));
+ assertThat(mPreference.isEnabled()).isTrue();
+ assertThat(mPreference.getMax()).isEqualTo(10);
+ assertThat(mPreference.getMin()).isEqualTo(1);
+ assertThat(mPreference.getProgress()).isEqualTo(7);
+ assertThat(mPreference.isVisible()).isTrue();
+ assertThat(mPreference.getOnPreferenceChangeListener()).isEqualTo(mController);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_COLOR_CORRECTION_SATURATION)
+ public void displayPreference_flagEnabledColorCorrectionDisabled_disabledWithDefaultValues() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 11);
+ mController.displayPreference(mScreen);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ assertThat(mPreference.getMax()).isEqualTo(10);
+ assertThat(mPreference.getMin()).isEqualTo(1);
+ assertThat(mPreference.getProgress()).isEqualTo(7);
+ assertThat(mPreference.isVisible()).isTrue();
+ assertThat(mPreference.getOnPreferenceChangeListener()).isEqualTo(mController);
}
@Test
@@ -132,12 +186,8 @@ public class DaltonizerSaturationSeekbarPreferenceControllerTest {
public void displayPreference_disabled_notVisible() {
mController.displayPreference(mScreen);
- verify(mPreference).setMax(eq(10));
- verify(mPreference).setMin(eq(0));
- verify(mPreference).setProgress(eq(7));
- verify(mPreference).setContinuousUpdates(eq(true));
- verify(mPreference, never()).setOnPreferenceChangeListener(any());
- verify(mPreference).setVisible(eq(false));
+ assertThat(mPreference.isVisible()).isFalse();
+ assertThat(mPreference.getOnPreferenceChangeListener()).isNull();
}
@Test
@@ -153,13 +203,13 @@ public class DaltonizerSaturationSeekbarPreferenceControllerTest {
@Test
public void setSliderPosition_min_secureSettingsUpdated() {
- var isSliderSet = mController.setSliderPosition(0);
+ var isSliderSet = mController.setSliderPosition(1);
assertThat(isSliderSet).isTrue();
assertThat(Settings.Secure.getInt(
mContentResolver,
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
- 7)).isEqualTo(0);
+ 7)).isEqualTo(1);
}
@Test
@@ -194,4 +244,140 @@ public class DaltonizerSaturationSeekbarPreferenceControllerTest {
Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_SATURATION_LEVEL,
7)).isEqualTo(7);
}
+
+ @Test
+ public void updateState_enabledProtan_preferenceEnabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void updateState_enabledDeuteran_preferenceEnabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 12);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void updateState_enabledTritan_preferenceEnabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 13);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void updateState_disabledGrayScale_preferenceDisabled() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 0);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void updateState_nullPreference_noError() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 0);
+
+ mController.updateState(null);
+ }
+
+ @Test
+ public void updateState_enabledGrayScale_preferenceDisabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 0);
+
+ mController.updateState(mPreference);
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void onResume_daltonizerEnabledAfterResumed_preferenceEnabled() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 11);
+ mController.displayPreference(mScreen);
+ assertThat(mPreference.isEnabled()).isFalse();
+
+ mLifecycle.addObserver(mController);
+ mLifecycle.handleLifecycleEvent(ON_RESUME);
+
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+ 1);
+ shadowOf(Looper.getMainLooper()).idle();
+
+ assertThat(mPreference.isEnabled()).isTrue();
+ }
+
+ @Test
+ public void onResume_daltonizerDisabledAfterResumed_preferenceDisabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
+ mController.displayPreference(mScreen);
+ assertThat(mPreference.isEnabled()).isTrue();
+
+ mLifecycle.addObserver(mController);
+ mLifecycle.handleLifecycleEvent(ON_RESUME);
+
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+ 0);
+ shadowOf(Looper.getMainLooper()).idle();
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void onResume_daltonizerGrayScaledAfterResumed_preferenceDisabled() {
+ setDaltonizerMode(/* enabled= */ 1, /* mode= */ 11);
+ mController.displayPreference(mScreen);
+ assertThat(mPreference.isEnabled()).isTrue();
+
+ mLifecycle.addObserver(mController);
+ mLifecycle.handleLifecycleEvent(ON_RESUME);
+
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+ 0);
+ shadowOf(Looper.getMainLooper()).idle();
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ @Test
+ public void onStop_daltonizerEnabledAfterOnStop_preferenceNotChanged() {
+ setDaltonizerMode(/* enabled= */ 0, /* mode= */ 11);
+ mController.displayPreference(mScreen);
+ assertThat(mPreference.isEnabled()).isFalse();
+
+ mLifecycle.addObserver(mController);
+ mLifecycle.handleLifecycleEvent(ON_STOP);
+
+ // enabled.
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+ 1);
+ shadowOf(Looper.getMainLooper()).idle();
+
+ assertThat(mPreference.isEnabled()).isFalse();
+ }
+
+ private void setDaltonizerMode(int enabled, int mode) {
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED,
+ enabled);
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER,
+ mode);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java
index a775731df59..4f8860e8832 100644
--- a/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/combination/CombinedBiometricProfileSettingsTest.java
@@ -127,8 +127,8 @@ public class CombinedBiometricProfileSettingsTest {
mFragment = spy(new TestCombinedBiometricProfileSettings(mContext));
doReturn(mActivity).when(mFragment).getActivity();
doReturn(mBiometricManager).when(mActivity).getSystemService(BiometricManager.class);
- when(mBiometricManager.canAuthenticate(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ when(mBiometricManager.canAuthenticate(anyInt(),
+ eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
.thenReturn(BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE);
ReflectionHelpers.setField(mFragment, "mDashboardFeatureProvider",
@@ -181,8 +181,8 @@ public class CombinedBiometricProfileSettingsTest {
public void testLaunchBiometricPrompt_onCreateFragment() {
ArgumentCaptor intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
doNothing().when(mFragment).startActivityForResult(any(), anyInt());
- when(mBiometricManager.canAuthenticate(
- BiometricManager.Authenticators.MANDATORY_BIOMETRICS))
+ when(mBiometricManager.canAuthenticate(anyInt(),
+ eq(BiometricManager.Authenticators.MANDATORY_BIOMETRICS)))
.thenReturn(BiometricManager.BIOMETRIC_SUCCESS);
mFragment.onAttach(mContext);
@@ -193,7 +193,7 @@ public class CombinedBiometricProfileSettingsTest {
Intent intent = intentArgumentCaptor.getValue();
assertThat(intent.getComponent().getClassName()).isEqualTo(
- ConfirmDeviceCredentialActivity.class.getName());
+ ConfirmDeviceCredentialActivity.InternalActivity.class.getName());
}
@Test
diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
index a34b6de5335..29b29614133 100644
--- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsFragmentTest.java
@@ -176,7 +176,7 @@ public class FingerprintSettingsFragmentTest {
Intent intent = intentArgumentCaptor.getValue();
assertThat(intent.getComponent().getClassName()).isEqualTo(
- ConfirmDeviceCredentialActivity.class.getName());
+ ConfirmDeviceCredentialActivity.InternalActivity.class.getName());
}
// Test the case when FingerprintAuthenticateSidecar receives an error callback from the
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceTest.java
index 13e2a9d4636..be62414253e 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceTest.java
@@ -117,6 +117,7 @@ public class AudioSharingNamePreferenceTest {
assertThat(shareButton.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(shareButton.getDrawable()).isNotNull();
assertThat(shareButton.hasOnClickListeners()).isTrue();
+ assertThat(shareButton.getContentDescription()).isNotNull();
assertThat(divider).isNotNull();
assertThat(divider.getVisibility()).isEqualTo(View.VISIBLE);
diff --git a/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
index bd005b3423c..978380ecfdd 100644
--- a/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/FreeformWindowsPreferenceControllerTest.java
@@ -16,8 +16,9 @@
package com.android.settings.development;
-import static com.android.settings.development.FreeformWindowsPreferenceController
- .SETTING_VALUE_OFF;
+import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+
+import static com.android.settings.development.FreeformWindowsPreferenceController.SETTING_VALUE_OFF;
import static com.android.settings.development.FreeformWindowsPreferenceController.SETTING_VALUE_ON;
import static com.google.common.truth.Truth.assertThat;
@@ -29,6 +30,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.provider.Settings;
import androidx.fragment.app.FragmentActivity;
@@ -43,7 +45,6 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@@ -52,9 +53,10 @@ import org.robolectric.annotation.Config;
})
public class FreeformWindowsPreferenceControllerTest {
- private static final String ENG_BUILD_TYPE = "eng";
- private static final String USER_BUILD_TYPE = "user";
-
+ @Mock
+ Context mContext;
+ @Mock
+ private PackageManager mPackageManager;
@Mock
private SwitchPreference mPreference;
@Mock
@@ -68,33 +70,33 @@ public class FreeformWindowsPreferenceControllerTest {
@Mock
private FragmentTransaction mTransaction;
- private Context mContext;
private FreeformWindowsPreferenceController mController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
doReturn(mTransaction).when(mFragmentManager).beginTransaction();
doReturn(mFragmentManager).when(mActivity).getSupportFragmentManager();
doReturn(mActivity).when(mFragment).getActivity();
mController = new FreeformWindowsPreferenceController(mContext, mFragment);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
mController.displayPreference(mScreen);
}
@Test
- public void isAvailable_engBuild_shouldBeTrue() {
+ public void isAvailable_deviceHasFreeformWindowSystemFeature_returnsFalse() {
mController = spy(mController);
- doReturn(ENG_BUILD_TYPE).when(mController).getBuildType();
+ when(mPackageManager.hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)).thenReturn(true);
- assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.isAvailable()).isFalse();
}
@Test
- public void isAvailable_userBuild_shouldBeTrue() {
+ public void isAvailable_deviceDoesNotHaveFreeformWindowSystemFeature_returnsTrue() {
mController = spy(mController);
- doReturn(USER_BUILD_TYPE).when(mController).getBuildType();
+ when(mPackageManager.hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)).thenReturn(
+ false);
assertThat(mController.isAvailable()).isTrue();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
index b949a3eb302..fdb075d2e03 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
@@ -389,6 +389,28 @@ public class BatteryHeaderPreferenceControllerTest {
verify(mBatteryUsageProgressBarPref).setBottomSummary(expectedChargingString);
}
+ @Test
+ public void updateBatteryStatus_dockDefend_chargingOnHold() {
+ var expected = "Charging on hold";
+ mBatteryInfo.isBatteryDefender = false;
+ when(mFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(true);
+
+ mController.updateBatteryStatus(/* label= */ null, mBatteryInfo);
+
+ verify(mBatteryUsageProgressBarPref).setBottomSummary(expected);
+ }
+
+ @Test
+ public void updateBatteryStatus_batteryDefender_chargingOnHold() {
+ var expected = "Charging on hold";
+ mBatteryInfo.isBatteryDefender = true;
+ when(mFactory.powerUsageFeatureProvider.isExtraDefend()).thenReturn(false);
+
+ mController.updateBatteryStatus(/* label= */ null, mBatteryInfo);
+
+ verify(mBatteryUsageProgressBarPref).setBottomSummary(expected);
+ }
+
private BatteryInfo arrangeUpdateBatteryStatusTestWithRemainingLabel(
String remainingLabel,
String statusLabel,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
index af0cb91752c..63d44d09a87 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBroadcastReceiverTest.java
@@ -28,9 +28,9 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.BatteryManager;
import android.os.SystemClock;
+import android.os.UserManager;
import android.text.format.DateUtils;
-import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
@@ -49,6 +49,7 @@ public final class BatteryUsageBroadcastReceiverTest {
private FakeFeatureFactory mFakeFeatureFactory;
@Mock private PackageManager mPackageManager;
+ @Mock private UserManager mUserManager;
@Before
public void setUp() {
@@ -57,6 +58,7 @@ public final class BatteryUsageBroadcastReceiverTest {
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mBatteryUsageBroadcastReceiver = new BatteryUsageBroadcastReceiver();
doReturn(mPackageManager).when(mContext).getPackageManager();
+ doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
DatabaseUtils.getSharedPreferences(mContext).edit().clear().apply();
}
@@ -69,7 +71,17 @@ public final class BatteryUsageBroadcastReceiverTest {
@Test
public void onReceive_workProfile_doNothing() {
- BatteryTestUtils.setWorkProfile(mContext);
+ doReturn(true).when(mUserManager).isManagedProfile();
+
+ mBatteryUsageBroadcastReceiver.onReceive(
+ mContext, new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING));
+
+ assertThat(mBatteryUsageBroadcastReceiver.mFetchBatteryUsageData).isFalse();
+ }
+
+ @Test
+ public void onReceive_privateProfile_doNothing() {
+ doReturn(true).when(mUserManager).isPrivateProfile();
mBatteryUsageBroadcastReceiver.onReceive(
mContext, new Intent(BatteryUsageBroadcastReceiver.ACTION_BATTERY_UNPLUGGING));
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
index 950f8280215..ac711a482af 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageContentProviderTest.java
@@ -19,12 +19,16 @@ package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.UserManager;
import androidx.test.core.app.ApplicationProvider;
@@ -39,6 +43,8 @@ import com.android.settings.testutils.FakeClock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import java.time.Duration;
@@ -62,9 +68,14 @@ public final class BatteryUsageContentProviderTest {
private Context mContext;
private BatteryUsageContentProvider mProvider;
+ @Mock
+ private UserManager mUserManager;
+
@Before
public void setUp() {
- mContext = ApplicationProvider.getApplicationContext();
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
mProvider = new BatteryUsageContentProvider();
mProvider.attachInfo(mContext, /* info= */ null);
BatteryTestUtils.setUpBatteryStateDatabase(mContext);
@@ -77,7 +88,13 @@ public final class BatteryUsageContentProviderTest {
@Test
public void onCreate_withWorkProfileMode_returnsFalse() {
- BatteryTestUtils.setWorkProfile(mContext);
+ doReturn(true).when(mUserManager).isManagedProfile();
+ assertThat(mProvider.onCreate()).isFalse();
+ }
+
+ @Test
+ public void onCreate_withPrivateProfileMode_returnsFalse() {
+ doReturn(true).when(mUserManager).isPrivateProfile();
assertThat(mProvider.onCreate()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java
index 704637f14c7..f318a2bcddf 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java
@@ -18,6 +18,9 @@ package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.app.AlarmManager;
@@ -26,6 +29,7 @@ import android.app.usage.UsageStatsManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.os.UserManager;
import androidx.test.core.app.ApplicationProvider;
@@ -37,6 +41,8 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowAlarmManager;
@@ -55,10 +61,15 @@ public final class BootBroadcastReceiverTest {
private ShadowAlarmManager mShadowAlarmManager;
private PeriodicJobManager mPeriodicJobManager;
+ @Mock
+ private UserManager mUserManager;
+
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
- mContext = ApplicationProvider.getApplicationContext();
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
mPeriodicJobManager = PeriodicJobManager.getInstance(mContext);
mShadowAlarmManager = shadowOf(mContext.getSystemService(AlarmManager.class));
mReceiver = new BootBroadcastReceiver();
@@ -78,7 +89,15 @@ public final class BootBroadcastReceiverTest {
@Test
public void onReceive_withWorkProfile_notRefreshesJob() {
- BatteryTestUtils.setWorkProfile(mContext);
+ doReturn(true).when(mUserManager).isManagedProfile();
+ mReceiver.onReceive(mContext, new Intent(Intent.ACTION_BOOT_COMPLETED));
+
+ assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
+ }
+
+ @Test
+ public void onReceive_withPrivateProfile_notRefreshesJob() {
+ doReturn(true).when(mUserManager).isPrivateProfile();
mReceiver.onReceive(mContext, new Intent(Intent.ACTION_BOOT_COMPLETED));
assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
index d89e61b00ea..2fda2779106 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/DatabaseUtilsTest.java
@@ -47,7 +47,6 @@ import android.os.UserManager;
import com.android.settings.fuelgauge.batteryusage.db.AppUsageEventEntity;
import com.android.settings.fuelgauge.batteryusage.db.BatteryEventEntity;
-import com.android.settings.testutils.BatteryTestUtils;
import org.junit.Before;
import org.junit.Test;
@@ -450,6 +449,26 @@ public final class DatabaseUtilsTest {
assertThat(batteryHistMap).isEmpty();
}
+ @Test
+ public void getHistoryMap_withPrivateProfile_returnExpectedMap()
+ throws PackageManager.NameNotFoundException {
+ doReturn("com.fake.package").when(mContext).getPackageName();
+ doReturn(mMockContext)
+ .when(mContext)
+ .createPackageContextAsUser("com.fake.package", /* flags= */ 0, UserHandle.OWNER);
+ doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
+ doReturn(UserHandle.CURRENT).when(mContext).getUser();
+ doReturn(true).when(mUserManager).isPrivateProfile();
+ doReturn(UserHandle.SYSTEM).when(mUserManager).getProfileParent(UserHandle.CURRENT);
+
+ DatabaseUtils.sFakeSupplier = () -> getMatrixCursor();
+
+ final Map> batteryHistMap =
+ DatabaseUtils.getHistoryMapSinceQueryTimestamp(mContext, 0);
+
+ assertThat(batteryHistMap).isEmpty();
+ }
+
@Test
public void removeUsageSource_hasNoData() {
DatabaseUtils.removeUsageSource(mContext);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiverTest.java
index d111de2160c..ea3c04c87c0 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiverTest.java
@@ -18,11 +18,15 @@ package com.android.settings.fuelgauge.batteryusage;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
import android.app.AlarmManager;
import android.content.Context;
import android.content.Intent;
+import android.os.UserManager;
import androidx.test.core.app.ApplicationProvider;
@@ -34,6 +38,8 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.shadows.ShadowAlarmManager;
@@ -53,12 +59,17 @@ public final class PeriodicJobReceiverTest {
private PeriodicJobManager mPeriodicJobManager;
private ShadowAlarmManager mShadowAlarmManager;
+ @Mock
+ private UserManager mUserManager;
+
@Before
public void setUp() {
- mContext = ApplicationProvider.getApplicationContext();
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
mPeriodicJobManager = PeriodicJobManager.getInstance(mContext);
mShadowAlarmManager = shadowOf(mContext.getSystemService(AlarmManager.class));
mReceiver = new PeriodicJobReceiver();
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
// Inserts fake data into database for testing.
final BatteryStateDatabase database = BatteryTestUtils.setUpBatteryStateDatabase(mContext);
@@ -114,7 +125,14 @@ public final class PeriodicJobReceiverTest {
@Test
public void onReceive_inWorkProfileMode_notRefreshesJob() {
- BatteryTestUtils.setWorkProfile(mContext);
+ doReturn(true).when(mUserManager).isManagedProfile();
+ mReceiver.onReceive(mContext, JOB_UPDATE_INTENT);
+ assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
+ }
+
+ @Test
+ public void onReceive_inPrivateProfileMode_notRefreshesJob() {
+ doReturn(true).when(mUserManager).isPrivateProfile();
mReceiver.onReceive(mContext, JOB_UPDATE_INTENT);
assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java
index d9981069a01..0dd18c54ae2 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java
@@ -18,7 +18,11 @@ package com.android.settings.fuelgauge.batteryusage.bugreport;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+
import android.content.Context;
+import android.os.UserManager;
import androidx.test.core.app.ApplicationProvider;
@@ -27,6 +31,8 @@ import com.android.settings.testutils.BatteryTestUtils;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import java.io.FileDescriptor;
@@ -46,11 +52,17 @@ public final class BugReportContentProviderTest {
private StringWriter mStringWriter;
private BugReportContentProvider mBugReportContentProvider;
+ @Mock
+ private UserManager mUserManager;
+
@Before
public void setUp() {
+ MockitoAnnotations.initMocks(this);
mStringWriter = new StringWriter();
mPrintWriter = new PrintWriter(mStringWriter);
- mContext = ApplicationProvider.getApplicationContext();
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ doReturn(mContext).when(mContext).getApplicationContext();
+ doReturn(mUserManager).when(mContext).getSystemService(UserManager.class);
mBugReportContentProvider = new BugReportContentProvider();
mBugReportContentProvider.attachInfo(mContext, /* info= */ null);
// Inserts fake data into database for testing.
@@ -77,7 +89,14 @@ public final class BugReportContentProviderTest {
@Test
public void dump_inWorkProfileMode_notDumpsBatteryUsageData() {
- BatteryTestUtils.setWorkProfile(mContext);
+ doReturn(true).when(mUserManager).isManagedProfile();
+ mBugReportContentProvider.dump(FileDescriptor.out, mPrintWriter, new String[] {});
+ assertThat(mStringWriter.toString()).isEmpty();
+ }
+
+ @Test
+ public void dump_inPrivateProfileMode_notDumpsBatteryUsageData() {
+ doReturn(true).when(mUserManager).isPrivateProfile();
mBugReportContentProvider.dump(FileDescriptor.out, mPrintWriter, new String[] {});
assertThat(mStringWriter.toString()).isEmpty();
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java
index fc3cef142c5..61ca4d84662 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetTriggerLinkPreferenceControllerTest.java
@@ -22,11 +22,15 @@ import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
-import static com.android.settings.notification.modes.ZenModeSetTriggerLinkPreferenceController.AUTOMATIC_TRIGGER_PREF_KEY;
+import static com.android.settings.notification.modes.ZenModeSetTriggerLinkPreferenceController.ADD_TRIGGER_KEY;
+import static com.android.settings.notification.modes.ZenModeSetTriggerLinkPreferenceController.AUTOMATIC_TRIGGER_KEY;
+import static com.android.settings.notification.modes.ZenModeSetTriggerLinkPreferenceControllerTest.CharSequenceTruth.assertThat;
+import static com.google.common.base.Preconditions.checkNotNull;
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.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -35,6 +39,7 @@ import android.app.AutomaticZenRule;
import android.app.Flags;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.platform.test.annotations.EnableFlags;
@@ -42,7 +47,11 @@ import android.platform.test.flag.junit.SetFlagsRule;
import android.service.notification.SystemZenRules;
import android.service.notification.ZenModeConfig;
+import androidx.annotation.Nullable;
+import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
@@ -53,6 +62,9 @@ import com.android.settingslib.notification.modes.TestModeBuilder;
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.notification.modes.ZenModesBackend;
+import com.google.common.truth.StringSubject;
+import com.google.common.truth.Truth;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -60,6 +72,7 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
import org.robolectric.RobolectricTestRunner;
import java.util.Calendar;
@@ -74,32 +87,47 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest {
private ZenModesBackend mBackend;
private Context mContext;
- private PrimarySwitchPreference mPreference;
-
@Mock
private PackageManager mPm;
@Mock
private ConfigurationActivityHelper mConfigurationActivityHelper;
- @Mock
private PreferenceCategory mPrefCategory;
+ private PrimarySwitchPreference mConfigPreference;
+ private Preference mAddPreference;
+
@Mock
private DashboardFragment mFragment;
- private ZenModeSetTriggerLinkPreferenceController mPrefController;
+ private ZenModeSetTriggerLinkPreferenceController mController;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
- mPrefController = new ZenModeSetTriggerLinkPreferenceController(mContext,
- "zen_automatic_trigger_category", mFragment, mBackend,
- mConfigurationActivityHelper,
- mock(ZenServiceListing.class));
- mPreference = new PrimarySwitchPreference(mContext);
+ PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ PreferenceScreen preferenceScreen = preferenceManager.inflateFromResource(mContext,
+ R.xml.modes_rule_settings, null);
- when(mPrefCategory.findPreference(AUTOMATIC_TRIGGER_PREF_KEY)).thenReturn(mPreference);
+ mController = new ZenModeSetTriggerLinkPreferenceController(mContext,
+ "zen_automatic_trigger_category", mFragment, mBackend, mPm,
+ mConfigurationActivityHelper, mock(ZenServiceListing.class));
+
+ mPrefCategory = preferenceScreen.findPreference("zen_automatic_trigger_category");
+ mConfigPreference = checkNotNull(mPrefCategory).findPreference(AUTOMATIC_TRIGGER_KEY);
+ mAddPreference = checkNotNull(mPrefCategory).findPreference(ADD_TRIGGER_KEY);
+
+ when(mPm.getApplicationInfo(any(), anyInt())).then(
+ (Answer) invocationOnMock -> {
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = invocationOnMock.getArgument(0);
+ appInfo.labelRes = 1; // Whatever, but != 0 so that loadLabel calls PM.getText()
+ return appInfo;
+ });
+ when(mPm.getText(any(), anyInt(), any())).then(
+ (Answer) invocationOnMock ->
+ "App named " + invocationOnMock.getArgument(0));
}
@Test
@@ -110,37 +138,37 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest {
.setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
.build(), true);
- mPrefController.updateZenMode(mPrefCategory, manualMode);
- assertThat(mPrefController.isAvailable()).isFalse();
+ mController.updateZenMode(mPrefCategory, manualMode);
+ assertThat(mController.isAvailable()).isFalse();
// should be available for other modes
- mPrefController.updateZenMode(mPrefCategory, TestModeBuilder.EXAMPLE);
- assertThat(mPrefController.isAvailable()).isTrue();
+ mController.updateZenMode(mPrefCategory, TestModeBuilder.EXAMPLE);
+ assertThat(mController.isAvailable()).isTrue();
}
@Test
- public void testUpdateState() {
+ public void updateState_switchCheckedIfRuleEnabled() {
ZenMode zenMode = new TestModeBuilder().setEnabled(false).build();
// Update preference controller with a zen mode that is not enabled
- mPrefController.updateZenMode(mPrefCategory, zenMode);
- assertThat(mPreference.getCheckedState()).isFalse();
+ mController.updateZenMode(mPrefCategory, zenMode);
+ assertThat(mConfigPreference.getCheckedState()).isFalse();
// Now with the rule enabled
zenMode.getRule().setEnabled(true);
- mPrefController.updateZenMode(mPrefCategory, zenMode);
- assertThat(mPreference.getCheckedState()).isTrue();
+ mController.updateZenMode(mPrefCategory, zenMode);
+ assertThat(mConfigPreference.getCheckedState()).isTrue();
}
@Test
- public void testOnPreferenceChange() {
+ public void onPreferenceChange_updatesMode() {
ZenMode zenMode = new TestModeBuilder().setEnabled(false).build();
// start with disabled rule
- mPrefController.updateZenMode(mPrefCategory, zenMode);
+ mController.updateZenMode(mPrefCategory, zenMode);
- // then update the preference to be checked
- mPrefController.mSwitchChangeListener.onPreferenceChange(mPreference, true);
+ // then flip the switch
+ mConfigPreference.callChangeListener(true);
// verify the backend got asked to update the mode to be enabled
ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class);
@@ -149,7 +177,7 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest {
}
@Test
- public void testRuleLink_calendar() {
+ public void updateState_scheduleCalendarRule() {
ZenModeConfig.EventInfo eventInfo = new ZenModeConfig.EventInfo();
eventInfo.calendarId = 1L;
eventInfo.calName = "My events";
@@ -159,23 +187,21 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest {
.setType(TYPE_SCHEDULE_CALENDAR)
.setTriggerDescription("My events")
.build();
- mPrefController.updateZenMode(mPrefCategory, mode);
- assertThat(mPreference.getTitle()).isNotNull();
- assertThat(mPreference.getTitle().toString()).isEqualTo(
- mContext.getString(R.string.zen_mode_set_calendar_link));
- assertThat(mPreference.getSummary()).isNotNull();
- assertThat(mPreference.getSummary().toString()).isEqualTo(
- mode.getRule().getTriggerDescription());
- assertThat(mPreference.getIcon()).isNull();
+ mController.updateState(mPrefCategory, mode);
+ assertThat(mAddPreference.isVisible()).isFalse();
+ assertThat(mConfigPreference.isVisible()).isTrue();
+ assertThat(mConfigPreference.getTitle()).isEqualTo("Calendar events");
+ assertThat(mConfigPreference.getSummary()).isEqualTo("My events");
// Destination as written into the intent by SubSettingLauncher
- assertThat(mPreference.getIntent().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
+ assertThat(
+ mConfigPreference.getIntent().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
.isEqualTo(ZenModeSetCalendarFragment.class.getName());
}
@Test
- public void testRuleLink_schedule() {
+ public void updateState_scheduleTimeRule() {
ZenModeConfig.ScheduleInfo scheduleInfo = new ZenModeConfig.ScheduleInfo();
scheduleInfo.days = new int[]{Calendar.MONDAY, Calendar.TUESDAY, Calendar.THURSDAY};
scheduleInfo.startHour = 1;
@@ -186,44 +212,41 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest {
.setType(TYPE_SCHEDULE_TIME)
.setTriggerDescription("some schedule")
.build();
- mPrefController.updateZenMode(mPrefCategory, mode);
- assertThat(mPreference.getTitle()).isNotNull();
- assertThat(mPreference.getTitle().toString()).isEqualTo(
- mContext.getString(R.string.zen_mode_set_schedule_link));
- assertThat(mPreference.getSummary()).isNotNull();
- assertThat(mPreference.getSummary().toString()).isEqualTo(
- mode.getRule().getTriggerDescription());
- assertThat(mPreference.getIcon()).isNull();
+ mController.updateState(mPrefCategory, mode);
+ assertThat(mAddPreference.isVisible()).isFalse();
+ assertThat(mConfigPreference.isVisible()).isTrue();
+ assertThat(mConfigPreference.getTitle()).isEqualTo("1:00 AM - 3:00 PM");
+ assertThat(mConfigPreference.getSummary()).isEqualTo("Mon - Tue, Thu");
// Destination as written into the intent by SubSettingLauncher
- assertThat(mPreference.getIntent().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
+ assertThat(
+ mConfigPreference.getIntent().getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT))
.isEqualTo(ZenModeSetScheduleFragment.class.getName());
}
@Test
- public void testRuleLink_manual() {
+ public void updateState_customManualRule() {
ZenMode mode = new TestModeBuilder()
.setConditionId(ZenModeConfig.toCustomManualConditionId())
.setPackage(SystemZenRules.PACKAGE_ANDROID)
.setType(TYPE_OTHER)
.setTriggerDescription("Will not be shown")
.build();
- mPrefController.updateZenMode(mPrefCategory, mode);
- assertThat(mPreference.getTitle()).isNotNull();
- assertThat(mPreference.getTitle().toString()).isEqualTo(
+ mController.updateState(mPrefCategory, mode);
+
+ assertThat(mConfigPreference.isVisible()).isFalse();
+ assertThat(mAddPreference.isVisible()).isTrue();
+ assertThat(mAddPreference.getTitle()).isEqualTo(
mContext.getString(R.string.zen_mode_select_schedule));
- assertThat(mPreference.getIcon()).isNotNull();
- assertThat(mPreference.getSummary()).isNotNull();
- assertThat(mPreference.getSummary().toString()).isEqualTo("");
-
- // Set up a click listener to open the dialog.
- assertThat(mPreference.getOnPreferenceClickListener()).isNotNull();
+ assertThat(mAddPreference.getSummary()).isNull();
+ // Sets up a click listener to open the dialog.
+ assertThat(mAddPreference.getOnPreferenceClickListener()).isNotNull();
}
@Test
- public void testRuleLink_appWithConfigActivity_linksToConfigActivity() {
+ public void updateState_appWithConfigActivity_showsLinkToConfigActivity() {
ZenMode mode = new TestModeBuilder()
.setPackage("some.package")
.setTriggerDescription("When The Music's Over")
@@ -232,28 +255,62 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest {
when(mConfigurationActivityHelper.getConfigurationActivityIntentForMode(any(), any()))
.thenReturn(configurationIntent);
- mPrefController.updateZenMode(mPrefCategory, mode);
+ mController.updateState(mPrefCategory, mode);
- assertThat(mPreference.getTitle()).isNotNull();
- assertThat(mPreference.getTitle().toString()).isEqualTo(
- mContext.getString(R.string.zen_mode_configuration_link_title));
- assertThat(mPreference.getSummary()).isNotNull();
- assertThat(mPreference.getSummary().toString()).isEqualTo("When The Music's Over");
- assertThat(mPreference.getIntent()).isEqualTo(configurationIntent);
+ assertThat(mConfigPreference.isVisible()).isTrue();
+ assertThat(mConfigPreference.getTitle()).isEqualTo("Linked to app");
+ assertThat(mConfigPreference.getSummary()).isEqualTo("When The Music's Over");
+ assertThat(mConfigPreference.getIntent()).isEqualTo(configurationIntent);
}
@Test
- public void testRuleLink_appWithoutConfigActivity_hidden() {
+ public void updateState_appWithoutConfigActivity_showsWithoutLinkToConfigActivity() {
ZenMode mode = new TestModeBuilder()
.setPackage("some.package")
- .setTriggerDescription("Will not be shown :(")
+ .setTriggerDescription("When the saints go marching in")
.build();
when(mConfigurationActivityHelper.getConfigurationActivityIntentForMode(any(), any()))
.thenReturn(null);
- mPrefController.updateZenMode(mPrefCategory, mode);
+ mController.updateState(mPrefCategory, mode);
- assertThat(mPrefCategory.isVisible()).isFalse();
+ assertThat(mConfigPreference.isVisible()).isTrue();
+ assertThat(mConfigPreference.getTitle()).isEqualTo("Linked to app");
+ assertThat(mConfigPreference.getSummary()).isEqualTo("When the saints go marching in");
+ assertThat(mConfigPreference.getIntent()).isNull();
+ }
+
+ @Test
+ public void updateState_appWithoutTriggerDescriptionWithConfigActivity_showsAppNameInSummary() {
+ ZenMode mode = new TestModeBuilder()
+ .setPackage("some.package")
+ .build();
+ Intent configurationIntent = new Intent("configure the mode");
+ when(mConfigurationActivityHelper.getConfigurationActivityIntentForMode(any(), any()))
+ .thenReturn(configurationIntent);
+ when(mPm.getText(any(), anyInt(), any())).thenReturn("The App Name");
+
+ mController.updateState(mPrefCategory, mode);
+
+ assertThat(mConfigPreference.isVisible()).isTrue();
+ assertThat(mConfigPreference.getTitle()).isEqualTo("Linked to app");
+ assertThat(mConfigPreference.getSummary()).isEqualTo("Info and settings in The App Name");
+ }
+
+ @Test
+ public void updateState_appWithoutTriggerDescriptionNorConfigActivity_showsAppNameInSummary() {
+ ZenMode mode = new TestModeBuilder()
+ .setPackage("some.package")
+ .build();
+ when(mConfigurationActivityHelper.getConfigurationActivityIntentForMode(any(), any()))
+ .thenReturn(null);
+ when(mPm.getText(any(), anyInt(), any())).thenReturn("The App Name");
+
+ mController.updateState(mPrefCategory, mode);
+
+ assertThat(mConfigPreference.isVisible()).isTrue();
+ assertThat(mConfigPreference.getTitle()).isEqualTo("Linked to app");
+ assertThat(mConfigPreference.getSummary()).isEqualTo("Managed by The App Name");
}
@Test
@@ -264,7 +321,7 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest {
.setType(TYPE_OTHER)
.setTriggerDescription("")
.build();
- mPrefController.updateZenMode(mPrefCategory, originalMode);
+ mController.updateZenMode(mPrefCategory, originalMode);
ZenModeConfig.ScheduleInfo scheduleInfo = new ZenModeConfig.ScheduleInfo();
scheduleInfo.days = new int[] { Calendar.MONDAY };
@@ -272,7 +329,7 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest {
scheduleInfo.endHour = 15;
Uri scheduleUri = ZenModeConfig.toScheduleConditionId(scheduleInfo);
- mPrefController.mOnScheduleOptionListener.onScheduleSelected(scheduleUri);
+ mController.mOnScheduleOptionListener.onScheduleSelected(scheduleUri);
// verify the backend got asked to update the mode to be schedule-based.
ArgumentCaptor captor = ArgumentCaptor.forClass(ZenMode.class);
@@ -284,4 +341,17 @@ public class ZenModeSetTriggerLinkPreferenceControllerTest {
assertThat(updatedMode.getRule().getOwner()).isEqualTo(
ZenModeConfig.getScheduleConditionProvider());
}
+
+ static class CharSequenceTruth {
+ /**
+ * Shortcut version of {@link Truth#assertThat(String)} suitable for {@link CharSequence}.
+ * {@link CharSequence} doesn't necessarily provide a good {@code equals()} implementation;
+ * however we don't care about formatting here, so we want to assert on the resulting
+ * string (without needing to worry that {@code assertThat(x.getText().toString())} can
+ * throw if the text is null).
+ */
+ static StringSubject assertThat(@Nullable CharSequence actual) {
+ return Truth.assertThat((String) (actual != null ? actual.toString() : null));
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
index 64a5f1169ef..c52fe2f2723 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowCrossProfileApps.java
@@ -19,9 +19,8 @@ package com.android.settings.testutils.shadow;
import android.Manifest;
import android.content.Context;
import android.content.pm.CrossProfileApps;
-import android.content.pm.ICrossProfileApps;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageInfo;
import androidx.annotation.NonNull;
@@ -35,15 +34,7 @@ import java.util.Set;
@Implements(CrossProfileApps.class)
public class ShadowCrossProfileApps extends org.robolectric.shadows.ShadowCrossProfileApps {
private static final Set configurableInteractAcrossProfilePackages = new HashSet<>();
- private Context mContext;
- private PackageManager mPackageManager;
- @Implementation
- protected void __constructor__(Context context, ICrossProfileApps service) {
- super.__constructor__(context, service);
- this.mContext = context;
- this.mPackageManager = context.getPackageManager();
- }
public void addCrossProfilePackage(String packageName) {
configurableInteractAcrossProfilePackages.add(packageName);
}
@@ -57,7 +48,9 @@ public class ShadowCrossProfileApps extends org.robolectric.shadows.ShadowCrossP
protected boolean canUserAttemptToConfigureInteractAcrossProfiles(@NonNull String packageName) {
PackageInfo packageInfo;
try {
- packageInfo = mPackageManager.getPackageInfo(packageName, /* flags= */ 0);
+ packageInfo = getContext().getPackageManager().getPackageInfo(
+ packageName,
+ /* flags= */ 0);
} catch (PackageManager.NameNotFoundException e) {
return false;
}
diff --git a/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java b/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java
index ab1f46926fa..2aa10bba45f 100644
--- a/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/development/bluetooth/BluetoothStackLogPreferenceControllerTest.java
@@ -16,13 +16,9 @@
package com.android.settings.development.bluetooth;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_VERBOSE_INDEX;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_DEBUG_INDEX;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_INFO_INDEX;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_WARN_INDEX;
-import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BTSTACK_LOG_MODE_ERROR_INDEX;
+import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BT_LOG_LEVEL_DEFAULT_INDEX;
+import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BT_LOG_LEVEL_PROP;
+import static com.android.settings.development.bluetooth.BluetoothStackLogPreferenceController.BT_LOG_LEVEL_PROP_PERSIST;
import static com.google.common.truth.Truth.assertThat;
@@ -37,18 +33,21 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
-@Ignore("b/339148064")
public class BluetoothStackLogPreferenceControllerTest {
- private static final String TAG = "BluetoothStackLogPreferenceControllerTest";
+ private static final String COM_ANDROID_SETTINGS = "com.android.settings";
+ private static final String TYPE_ARRAY = "array";
- @Mock private Context mContext;
+ private static final String XML_DEFINED_PREFERENCE_KEY = "bt_stack_log_level";
+ private static final String XML_DEFINED_ENTRIES_RESOURCE = "bt_stack_log_level_entries";
+ private static final String XML_DEFINED_VALUES_RESOURCE = "bt_stack_log_level_values";
+
+ private static final String PROPERTY_CLEARED = "";
+
+ private Context mContext;
private ListPreference mPreference;
private PreferenceManager mPreferenceManager;
@@ -61,7 +60,6 @@ public class BluetoothStackLogPreferenceControllerTest {
@Before
public void setup() {
- MockitoAnnotations.initMocks(this);
mContext = ApplicationProvider.getApplicationContext();
if (Looper.myLooper() == null) {
@@ -71,12 +69,11 @@ public class BluetoothStackLogPreferenceControllerTest {
mPreferenceManager = new PreferenceManager(mContext);
mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
mPreference = new ListPreference(mContext);
-
mController = new BluetoothStackLogPreferenceController(mContext);
mPreference.setKey(mController.getPreferenceKey());
- mPreference.setEntries(com.android.settings.R.array.bt_stack_log_level_entries);
- mPreference.setEntryValues(com.android.settings.R.array.bt_stack_log_level_values);
+ mPreference.setEntries(getStringArrayResourceId(XML_DEFINED_ENTRIES_RESOURCE));
+ mPreference.setEntryValues(getStringArrayResourceId(XML_DEFINED_VALUES_RESOURCE));
mPreferenceScreen.addPreference(mPreference);
mController.displayPreference(mPreferenceScreen);
@@ -86,134 +83,109 @@ public class BluetoothStackLogPreferenceControllerTest {
}
/**
- * Test that default log level is set to INFO
+ * Get the resource ID associated with a resource name
+ *
+ * This looks up the resource id by name using our device's context. This way, we can avoid
+ * hardcoding a resource ID or value from the R class which may not match the resource IDs on
+ * the device under test.
+ *
+ * Usage: int valuesResId = getStringArrayResource("bt_stack_log_level_values");
+ * Usage: int entriesResId = getStringArrayResource("bt_stack_log_level_entries");
+ *
+ * @param res - The resource name to look up
+ * @return The integer resource ID corresponding to the given resource name
*/
- @Test
- public void verifyDefaultState_enablesDefaultLogLevelEntriesAndValuesSameSize() {
- mController.onPreferenceChange(mPreference, mController.getDefaultModeIndex());
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
- [BTSTACK_LOG_MODE_INFO_INDEX].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
- [BTSTACK_LOG_MODE_INFO_INDEX].toString());
+ public int getStringArrayResourceId(String res) {
+ return mContext.getResources().getIdentifier(res, TYPE_ARRAY, COM_ANDROID_SETTINGS);
}
/**
- * Test that log level is changed to VERBOSE when VERBOSE is selected
+ * Test that, for each possible value a user can select, our controller properly handles the
+ * value to update the underlying system property _and_ set the UI entry to the proper value.
*/
@Test
- public void onPreferenceChanged_enableBluetoothStackVerboseLogLevel() {
- mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_VERBOSE_INDEX]
- .toString());
+ public void onPreferenceChange_withEachValue_uiSetProperlyAndAllValuesWrittenToProperties() {
+ for (int index = 0; index < mListValues.length; index++) {
+ String value = mListValues[index].toString();
+ String entry = mListEntries[index].toString();
- final String persistedLogLevel = SystemProperties.get(
- BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
- final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
- assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_VERBOSE_INDEX]
- .toString());
- assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_VERBOSE_INDEX].toString());
+ mController.onPreferenceChange(mPreference, value);
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
- [BTSTACK_LOG_MODE_VERBOSE_INDEX].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
- [BTSTACK_LOG_MODE_VERBOSE_INDEX].toString());
+ final String persistedLogLevel = SystemProperties.get(BT_LOG_LEVEL_PROP_PERSIST);
+ final String logLevel = SystemProperties.get(BT_LOG_LEVEL_PROP);
+ final String currentValue = mPreference.getValue().toString();
+ final String currentEntry = mPreference.getEntry().toString();
+ final String currentSummary = mPreference.getSummary().toString();
+ final int currentIndex = mPreference.findIndexOfValue(currentValue);
+
+ assertThat(persistedLogLevel).isEqualTo(value);
+ assertThat(logLevel).isEqualTo(value);
+ assertThat(currentIndex).isEqualTo(index);
+ assertThat(currentValue).isEqualTo(value);
+ assertThat(currentEntry).isEqualTo(entry);
+ assertThat(currentSummary).isEqualTo(entry);
+ }
}
/**
- * Test that log level is changed to DEBUG when DEBUG is selected
+ * Test that, for each possible log tag log level value, our controller properly handles the
+ * value to set the UI entry to the proper value.
*/
@Test
- public void onPreferenceChanged_enableBluetoothStackDebugLogLevel() {
- mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_DEBUG_INDEX]
- .toString());
+ public void updateState_withEachValue_uiSetProperly() {
+ for (int index = 0; index < mListValues.length; index++) {
+ String value = mListValues[index].toString();
+ String entry = mListEntries[index].toString();
- final String persistedLogLevel = SystemProperties.get(
- BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
- final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
- assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_DEBUG_INDEX]
- .toString());
- assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_DEBUG_INDEX].toString());
+ SystemProperties.set(BT_LOG_LEVEL_PROP_PERSIST, value);
+ SystemProperties.set(BT_LOG_LEVEL_PROP, value);
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
- [BTSTACK_LOG_MODE_DEBUG_INDEX].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
- [BTSTACK_LOG_MODE_DEBUG_INDEX].toString());
+ mController.updateState(mPreference);
+
+ final String currentValue = mPreference.getValue().toString();
+ final String currentEntry = mPreference.getEntry().toString();
+ final String currentSummary = mPreference.getSummary().toString();
+ final int currentIndex = mPreference.findIndexOfValue(currentValue);
+
+ assertThat(currentIndex).isEqualTo(index);
+ assertThat(currentValue).isEqualTo(value);
+ assertThat(currentEntry).isEqualTo(entry);
+ assertThat(currentSummary).isEqualTo(entry);
+ }
}
/**
- * Test that log level is changed to INFO when INFO is selected
+ * Test that our controller reverts the log level back to a missing/default value when we're
+ * notified that Developer Options has been disabled.
*/
@Test
- public void onPreferenceChanged_enableBluetoothStackInfoLogLevel() {
- mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_INFO_INDEX]
- .toString());
+ public void onDeveloperOptionsSwitchDisabled_preferenceSetToDefault() {
+ mController.onDeveloperOptionsSwitchDisabled();
- final String persistedLogLevel = SystemProperties.get(
- BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
- final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
- assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_INFO_INDEX]
- .toString());
- assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_INFO_INDEX].toString());
+ final String defaultEntry = mListEntries[BT_LOG_LEVEL_DEFAULT_INDEX].toString();
+ final String defaultValue = mListValues[BT_LOG_LEVEL_DEFAULT_INDEX].toString();
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
- [BTSTACK_LOG_MODE_INFO_INDEX].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
- [BTSTACK_LOG_MODE_INFO_INDEX].toString());
+ final String persistedLogLevel = SystemProperties.get(BT_LOG_LEVEL_PROP_PERSIST);
+ final String logLevel = SystemProperties.get(BT_LOG_LEVEL_PROP);
+ final String currentValue = mPreference.getValue().toString();
+ final String currentEntry = mPreference.getEntry().toString();
+ final String currentSummary = mPreference.getSummary().toString();
+ final int currentIndex = mPreference.findIndexOfValue(currentValue);
+
+ assertThat(persistedLogLevel).isEqualTo(PROPERTY_CLEARED);
+ assertThat(logLevel).isEqualTo(PROPERTY_CLEARED);
+ assertThat(currentIndex).isEqualTo(BT_LOG_LEVEL_DEFAULT_INDEX);
+ assertThat(currentValue).isEqualTo(defaultValue);
+ assertThat(currentEntry).isEqualTo(defaultEntry);
+ assertThat(currentSummary).isEqualTo(defaultEntry);
}
/**
- * Test that log level is changed to WARN when WARN is selected
+ * Test that our preference key returned by our controller matches the one defined in the XML
+ * definition.
*/
@Test
- public void onPreferenceChanged_enableBluetoothStackWarnLogLevel() {
- mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_WARN_INDEX]
- .toString());
-
- final String persistedLogLevel = SystemProperties.get(
- BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
- final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
- assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_WARN_INDEX]
- .toString());
- assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_WARN_INDEX].toString());
-
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
-
- [BTSTACK_LOG_MODE_WARN_INDEX].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
- [BTSTACK_LOG_MODE_WARN_INDEX].toString());
- }
-
- /**
- * Test that log level is changed to ERROR when ERROR is selected
- */
- @Test
- public void onPreferenceChanged_enableBluetoothStackErrorLogLevel() {
- mController.onPreferenceChange(mPreference, mListValues[BTSTACK_LOG_MODE_ERROR_INDEX]
- .toString());
-
- final String persistedLogLevel = SystemProperties.get(
- BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY_PERSIST);
- final String logLevel = SystemProperties.get(BLUETOOTH_BTSTACK_LOG_MODE_PROPERTY);
- assertThat(persistedLogLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_ERROR_INDEX]
- .toString());
- assertThat(logLevel).isEqualTo(mListValues[BTSTACK_LOG_MODE_ERROR_INDEX].toString());
-
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues
- [BTSTACK_LOG_MODE_ERROR_INDEX].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries
- [BTSTACK_LOG_MODE_ERROR_INDEX].toString());
- }
-
- /**
- * Test that preference is disabled when developer options is disabled
- * Log level is also reset to default
- */
- @Test
- public void onDeveloperOptionsDisabled_shouldDisablePreference() {
- mController.onDeveloperOptionsDisabled();
- assertThat(mPreference.isEnabled()).isFalse();
- assertThat(mPreference.getValue().toString()).isEqualTo(mListValues[mController
- .getDefaultModeIndex()].toString());
- assertThat(mPreference.getSummary().toString()).isEqualTo(mListEntries[mController
- .getDefaultModeIndex()].toString());
+ public void getPreferenceKey_matchesXmlDefinedPreferenceKey() {
+ assertThat(mController.getPreferenceKey()).isEqualTo(XML_DEFINED_PREFERENCE_KEY);
}
}