Merge "Add developer option for screenshare protections" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c8f35ae..96b798a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3232,7 +3232,8 @@
<receiver
android:name=".fuelgauge.batteryusage.BootBroadcastReceiver"
- android:exported="true">
+ android:exported="true"
+ android:permission="com.android.settings.BATTERY_DATA">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="com.google.android.setupwizard.SETUP_WIZARD_FINISHED"/>
diff --git a/OWNERS b/OWNERS
index 6698752..12cd4ea 100644
--- a/OWNERS
+++ b/OWNERS
@@ -11,7 +11,6 @@
jiannan@google.com
millchen@google.com
sunnyshao@google.com
-yantingyang@google.com
# Android Settings extended
chaohuiw@google.com
diff --git a/aconfig/settings_connecteddevice_flag_declarations.aconfig b/aconfig/settings_connecteddevice_flag_declarations.aconfig
index 5ba2129..0fc164e 100644
--- a/aconfig/settings_connecteddevice_flag_declarations.aconfig
+++ b/aconfig/settings_connecteddevice_flag_declarations.aconfig
@@ -33,4 +33,11 @@
namespace: "pixel_cross_device_control"
description: "Order the saved bluetooth devices by most recently connected."
bug: "306160434"
+}
+
+flag {
+ name: "enable_hide_exclusively_managed_bluetooth_device"
+ namespace: "dck_framework"
+ description: "Hide exclusively managed Bluetooth devices in BT settings menu."
+ bug: "322285078"
}
\ No newline at end of file
diff --git a/aconfig/settings_flag_declarations.aconfig b/aconfig/settings_flag_declarations.aconfig
index 56c4b32..36f104c 100644
--- a/aconfig/settings_flag_declarations.aconfig
+++ b/aconfig/settings_flag_declarations.aconfig
@@ -13,3 +13,10 @@
description: "Enabling will provide an explicit package name for Intent to update mainline modules"
bug: "278987474"
}
+
+flag {
+ name: "app_archiving"
+ namespace: "android_settings"
+ description: "Feature flag to enable the archiving feature."
+ bug: "323164382"
+}
diff --git a/res/values/strings.xml b/res/values/strings.xml
index c26e316..9762f83 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -7265,7 +7265,7 @@
<!-- Summary text describing signal strength to the user. [CHAR LIMIT=60] -->
<string name="sim_signal_strength"><xliff:g id="dbm">%1$d</xliff:g> dBm <xliff:g id="asu">%2$d</xliff:g> asu</string>
<!-- Title for SIM notification. [CHAR LIMIT=40] -->
- <string name="sim_notification_title">SIMs changed.</string>
+ <string name="sim_notification_title">Your SIMs changed</string>
<!-- Message under title informing the user to touch to go to SIM Cards in Settings. [CHAR LIMIT=40] -->
<string name="sim_notification_summary">Tap to set up</string>
@@ -9055,7 +9055,7 @@
<string name="screen_pinning_unlock_none">Lock device when unpinning</string>
<!-- [CHAR LIMIT=60] turn eSim deletion confirmation on/off -->
- <string name="confirm_sim_deletion_title">Confirm SIM deletion</string>
+ <string name="confirm_sim_deletion_title">Confirm you want to erase your eSIM</string>
<!-- [CHAR LIMIT=NONE] eSim deletion confirmation description -->
<string name="confirm_sim_deletion_description">Verify it\u0027s you before erasing an eSIM</string>
@@ -11370,7 +11370,7 @@
the user that the way to disable this SIM is to physically remove it. This is in contrast
to eSIM's, which can disabled using an on/off toggle switch. [CHAR LIMIT=NONE] -->
<string name="mobile_network_disable_sim_explanation">
- To disable this SIM, remove the SIM card
+ To turn off this SIM, remove the SIM card
</string>
<!--Summary used when a physical SIM is disabled, indicating that tapping on the preference will
@@ -11378,7 +11378,7 @@
Network & internet page (if there are no other SIMs), or on the mobile network list page.
[CHAR LIMIT=50] -->
<string name="mobile_network_tap_to_activate">
- Tap to activate <xliff:g id="carrier" example="T-mobile">%1$s</xliff:g>
+ Tap to activate your <xliff:g id="carrier" example="T-mobile">%1$s</xliff:g> SIM
</string>
<!-- Mobile network details page. Label for an option that lets the user delete an eSIM from
@@ -11502,13 +11502,13 @@
<!-- Text of carrier list item in the mep confirmation dialog asking the user if they want to turn off the carrier. [CHAR_LIMIT=NONE] -->
<string name="sim_action_switch_sub_dialog_info_outline_for_turning_off">Turning off a SIM won\u2019t cancel your service</string>
<!-- Status message indicating the device is in the process of disconnecting from one mobile network and immediately connecting to another. [CHAR_LIMIT=NONE] -->
- <string name="sim_action_enabling_sim_without_carrier_name">Connecting to network…</string>
+ <string name="sim_action_enabling_sim_without_carrier_name">Activating your SIM…</string>
<!-- Text of progress dialog indicating the subscription switch is in progress. [CHAR_LIMIT=NONE] -->
- <string name="sim_action_switch_sub_dialog_progress">Switching to <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g> for calls and messages…</string>
+ <string name="sim_action_switch_sub_dialog_progress">Switching to <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>…</string>
<!-- Title of error message indicating that the device could not disconnect from one mobile network and immediately connect to another. [CHAR_LIMIT=NONE] -->
- <string name="sim_action_enable_sim_fail_title">Can\u2019t switch carrier</string>
+ <string name="sim_action_enable_sim_fail_title">Can\u2019t switch SIMs</string>
<!-- Body text of error message indicating the device could not disconnect from one mobile network and immediately connect to another, due to an unspecified issue. [CHAR_LIMIT=NONE] -->
- <string name="sim_action_enable_sim_fail_text">The carrier can\u2019t be switched due to an error.</string>
+ <string name="sim_action_enable_sim_fail_text">Something went wrong. Can\u2019t switch SIMs.</string>
<!-- Title of confirmation dialog asking the user if they want to disable subscription. [CHAR_LIMIT=NONE] -->
<string name="privileged_action_disable_sub_dialog_title">Turn off <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g>?</string>
<!-- Title of confirmation dialog asking the user if they want to disable subscription. [CHAR_LIMIT=NONE] -->
@@ -11516,9 +11516,9 @@
<!-- Disabling SIMs progress dialog message [CHAR LIMIT=NONE] -->
<string name="privileged_action_disable_sub_dialog_progress">Turning off SIM<xliff:g id="ellipsis" example="...">…</xliff:g></string>
<!-- Title of error messaging indicating the device could not disable the mobile network. [CHAR LIMIT=NONE] -->
- <string name="privileged_action_disable_fail_title">Can\u2019t disable carrier</string>
+ <string name="privileged_action_disable_fail_title">Can\u2019t turn off SIM</string>
<!-- Body text of error message indicating the device could not disable the mobile network, due to an unknown issue. [CHAR LIMIT=NONE] -->
- <string name="privileged_action_disable_fail_text">Something went wrong and your carrier could not be disabled.</string>
+ <string name="privileged_action_disable_fail_text">Something went wrong and your SIM could not be turned off.</string>
<!-- Title on a dialog asking the users whether they want to enable DSDS mode. [CHAR LIMIT=NONE] -->
<string name="sim_action_enable_dsds_title">Use 2 SIMs?</string>
<!-- Message in a dialog indicating the user can enable DSDS mode. [CHAR LIMIT=NONE] -->
@@ -11598,7 +11598,7 @@
<!-- Title on a push notification indicating that the user's device is in the middle of switching between mobile networks. [CHAR LIMIT=NONE] -->
<string name="sim_switch_channel_id">Carrier switching</string>
<!-- The title of post DSDS reboot notification. The title includes carrier's name. [CHAR LIMIT=NONE] -->
- <string name="post_dsds_reboot_notification_title_with_carrier"><xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g> is active</string>
+ <string name="post_dsds_reboot_notification_title_with_carrier">Your <xliff:g id="carrier_name" example="Google Fi">%1$s</xliff:g> SIM is active</string>
<!-- The body text of post DSDS reboot notification. [CHAR LIMIT=NONE] -->
<string name="post_dsds_reboot_notification_text">Tap to update SIM settings</string>
<!-- Title on a push notification indicating that the user's device switched to a new mobile network. [CHAR LIMIT=NONE] -->
@@ -11614,17 +11614,17 @@
<!-- Strings for choose SIM activity -->
<!-- The title text of choose SIM activity. [CHAR LIMIT=NONE] -->
- <string name="choose_sim_title">Choose a number to use</string>
+ <string name="choose_sim_title">Choose a SIM to use</string>
<!-- The body text of choose SIM activity. [CHAR LIMIT=NONE] -->
<string name="choose_sim_text">{count, plural,
- =1 {1 number is available on this device, but only one can be used at a time}
- =2 {2 numbers are available on this device, but only one can be used at a time}
- other {# numbers are available on this device, but only one can be used at a time}
+ =1 {1 SIM is available on this device, but only one can be used at a time}
+ =2 {2 SIMs are available on this device, but only one can be used at a time}
+ other {# SIMs are available on this device, but only one can be used at a time}
}</string>
<!-- String indicating that we are activating the profile [CHAR LIMIT=NONE] -->
<string name="choose_sim_activating">Activating<xliff:g id="ellipsis" example="...">…</xliff:g></string>
<!-- String indicating that we failed to activate the selected profile [CHAR LIMIT=NONE] -->
- <string name="choose_sim_could_not_activate">Couldn\u2019t be activated right now</string>
+ <string name="choose_sim_could_not_activate">Couldn\u2019t activate this SIM right now</string>
<!-- Strings for switch SIM confirmation dialog. -->
<!-- The title text of switch SIM confirmation dialog. [CHAR LIMIT=NONE] -->
diff --git a/src/com/android/settings/applications/AppCounter.java b/src/com/android/settings/applications/AppCounter.java
index d536932..2b1e47e 100644
--- a/src/com/android/settings/applications/AppCounter.java
+++ b/src/com/android/settings/applications/AppCounter.java
@@ -22,12 +22,15 @@
import android.content.pm.PackageManager.ApplicationInfoFlags;
import android.content.pm.UserInfo;
import android.os.AsyncTask;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.android.settings.flags.Flags;
+
import java.util.List;
public abstract class AppCounter extends AsyncTask<Void, Void, Integer> {
@@ -54,7 +57,7 @@
for (UserInfo user : mUm.getProfiles(UserHandle.myUserId())) {
long flags = PackageManager.GET_DISABLED_COMPONENTS
| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS
- | (mFf.archiving() ? PackageManager.MATCH_ARCHIVED_PACKAGES : 0)
+ | (isArchivingEnabled() ? PackageManager.MATCH_ARCHIVED_PACKAGES : 0)
| (user.isAdmin() ? PackageManager.MATCH_ANY_USER : 0);
ApplicationInfoFlags infoFlags = ApplicationInfoFlags.of(flags);
final List<ApplicationInfo> list =
@@ -68,6 +71,11 @@
return count;
}
+ private boolean isArchivingEnabled() {
+ return mFf.archiving() || SystemProperties.getBoolean("pm.archiving.enabled", false)
+ || Flags.appArchiving();
+ }
+
@Override
protected void onPostExecute(Integer count) {
onCountComplete(count);
diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
index 2f04b62..4fc0e16 100644
--- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
@@ -46,6 +46,7 @@
import android.service.autofill.AutofillServiceInfo;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
import android.view.View;
import android.widget.CompoundButton;
@@ -77,6 +78,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -114,7 +116,7 @@
private @Nullable String mFlagOverrideForTest = null;
private @Nullable PreferenceScreen mPreferenceScreen = null;
- private boolean mVisibility = false;
+ private Optional<Boolean> mSimulateHiddenForTests = Optional.empty();
private boolean mIsWorkProfile = false;
private boolean mSimulateConnectedForTests = false;
@@ -159,7 +161,9 @@
return UNSUPPORTED_ON_DEVICE;
}
- if (!mVisibility) {
+ // If there is no top provider or any providers in the list then
+ // we should hide this pref.
+ if (isHiddenDueToNoProviderSet()) {
return CONDITIONALLY_UNAVAILABLE;
}
@@ -378,20 +382,29 @@
}
@VisibleForTesting
- public void setVisibility(boolean newVisibility) {
- if (newVisibility == mVisibility) {
- return;
- }
-
- mVisibility = newVisibility;
+ public void forceDelegateRefresh() {
if (mDelegate != null) {
mDelegate.forceDelegateRefresh();
}
}
@VisibleForTesting
- public boolean getVisibility() {
- return mVisibility;
+ public void setSimulateHiddenForTests(Optional<Boolean> simulateHiddenForTests) {
+ mSimulateHiddenForTests = simulateHiddenForTests;
+ }
+
+ @VisibleForTesting
+ public boolean isHiddenDueToNoProviderSet() {
+ return isHiddenDueToNoProviderSet(getProviders());
+ }
+
+ private boolean isHiddenDueToNoProviderSet(
+ Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair) {
+ if (mSimulateHiddenForTests.isPresent()) {
+ return mSimulateHiddenForTests.get();
+ }
+
+ return (providerPair.first.size() == 0 || providerPair.second == null);
}
@VisibleForTesting
@@ -459,10 +472,11 @@
return preference;
}
- /** Aggregates the list of services and builds a list of UI prefs to show. */
- @VisibleForTesting
- public Map<String, CombiPreference> buildPreferenceList(
- Context context, PreferenceGroup group) {
+ /**
+ * Returns a pair that contains a list of the providers in the first position and the top
+ * provider in the second position.
+ */
+ private Pair<List<CombinedProviderInfo>, CombinedProviderInfo> getProviders() {
// Get the selected autofill provider. If it is the placeholder then replace it with an
// empty string.
String selectedAutofillProvider =
@@ -475,15 +489,25 @@
// Get the list of combined providers.
List<CombinedProviderInfo> providers =
CombinedProviderInfo.buildMergedList(
- AutofillServiceInfo.getAvailableServices(context, getUser()),
+ AutofillServiceInfo.getAvailableServices(mContext, getUser()),
mServices,
selectedAutofillProvider);
+ return new Pair<>(providers, CombinedProviderInfo.getTopProvider(providers));
+ }
- // Get the provider that is displayed at the top. If there is none then hide
- // everything.
- CombinedProviderInfo topProvider = CombinedProviderInfo.getTopProvider(providers);
- if (topProvider == null) {
- setVisibility(false);
+ /** Aggregates the list of services and builds a list of UI prefs to show. */
+ @VisibleForTesting
+ public @NonNull Map<String, CombiPreference> buildPreferenceList(
+ @NonNull Context context, @NonNull PreferenceGroup group) {
+ // Get the providers and extract the values.
+ Pair<List<CombinedProviderInfo>, CombinedProviderInfo> providerPair = getProviders();
+ CombinedProviderInfo topProvider = providerPair.second;
+ List<CombinedProviderInfo> providers = providerPair.first;
+
+ // If the provider is set to "none" or there are no providers then we should not
+ // return any providers.
+ if (isHiddenDueToNoProviderSet(providerPair)) {
+ forceDelegateRefresh();
return new HashMap<>();
}
@@ -520,7 +544,7 @@
}
// Set the visibility if we have services.
- setVisibility(!output.isEmpty());
+ forceDelegateRefresh();
return output;
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
index 18ad210..3d85ca2 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsHearingDeviceControlsController.java
@@ -38,7 +38,8 @@
public class BluetoothDetailsHearingDeviceControlsController extends BluetoothDetailsController
implements Preference.OnPreferenceClickListener {
- private static final String KEY_DEVICE_CONTROLS_GENERAL_GROUP = "device_controls_general";
+ @VisibleForTesting
+ static final String KEY_DEVICE_CONTROLS_GENERAL_GROUP = "device_controls_general";
@VisibleForTesting
static final String KEY_HEARING_DEVICE_CONTROLS = "hearing_device_controls";
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 5e41a20..9c68c9c 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -22,6 +22,7 @@
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
+import android.content.Intent;
import android.content.res.TypedArray;
import android.hardware.input.InputManager;
import android.net.Uri;
@@ -53,6 +54,7 @@
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
@@ -324,8 +326,11 @@
lifecycle));
controllers.add(new BluetoothDetailsPairOtherController(context, this, mCachedDevice,
lifecycle));
- controllers.add(new BluetoothDetailsHearingDeviceControlsController(context, this,
- mCachedDevice, lifecycle));
+ // Don't need to show hearing device again when launched from the same page.
+ if (!isLaunchFromHearingDevicePage()) {
+ controllers.add(new BluetoothDetailsHearingDeviceControlsController(context, this,
+ mCachedDevice, lifecycle));
+ }
controllers.add(new BluetoothDetailsDataSyncController(context, this,
mCachedDevice, lifecycle));
controllers.add(
@@ -348,6 +353,16 @@
return width;
}
+ private boolean isLaunchFromHearingDevicePage() {
+ final Intent intent = getIntent();
+ if (intent == null) {
+ return false;
+ }
+
+ return intent.getIntExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
+ SettingsEnums.PAGE_UNKNOWN) == SettingsEnums.ACCESSIBILITY_HEARING_AID_SETTINGS;
+ }
+
@VisibleForTesting
void setTitleForInputDevice() {
if (StylusDevicesController.isDeviceStylus(mInputDevice, mCachedDevice)) {
diff --git a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
index 489c095..012220c 100644
--- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
@@ -24,6 +24,8 @@
import androidx.preference.Preference;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.flags.Flags;
+import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
/**
@@ -95,6 +97,15 @@
cachedDevice.getName() + ", isFilterMatched : " + isFilterMatched);
}
}
+ if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
+ if (BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext,
+ cachedDevice.getDevice())) {
+ if (DBG) {
+ Log.d(TAG, "isFilterMatched() hide BluetoothDevice with exclusive manager");
+ }
+ return false;
+ }
+ }
return isFilterMatched;
}
diff --git a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
index bfd4221..1db90fa 100644
--- a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
@@ -25,6 +25,8 @@
import androidx.preference.Preference;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.flags.Flags;
+import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
@@ -99,12 +101,22 @@
@Override
public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
final BluetoothDevice device = cachedDevice.getDevice();
- Log.d(TAG, "isFilterMatched() device name : " + cachedDevice.getName() +
- ", is connected : " + device.isConnected() + ", is profile connected : "
- + cachedDevice.isConnected());
- return device.getBondState() == BluetoothDevice.BOND_BONDED
- && (mShowConnectedDevice || (!device.isConnected() && isDeviceInCachedDevicesList(
- cachedDevice)));
+ boolean isExclusivelyManaged = BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext,
+ cachedDevice.getDevice());
+ Log.d(TAG, "isFilterMatched() device name : " + cachedDevice.getName()
+ + ", is connected : " + device.isConnected() + ", is profile connected : "
+ + cachedDevice.isConnected() + ", is exclusively managed : "
+ + isExclusivelyManaged);
+ if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
+ return device.getBondState() == BluetoothDevice.BOND_BONDED
+ && (mShowConnectedDevice || (!device.isConnected()
+ && isDeviceInCachedDevicesList(cachedDevice)))
+ && !isExclusivelyManaged;
+ } else {
+ return device.getBondState() == BluetoothDevice.BOND_BONDED
+ && (mShowConnectedDevice || (!device.isConnected()
+ && isDeviceInCachedDevicesList(cachedDevice)));
+ }
}
@Override
diff --git a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java
index cc333a5..62be5df 100644
--- a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java
+++ b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProvider.java
@@ -18,6 +18,7 @@
import android.content.Context;
+import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import java.util.List;
@@ -35,5 +36,9 @@
boolean isBatteryInfoEnabled(Context context);
/** A way to add more battery tip detectors. */
- void addBatteryTipDetector(Context context, List<BatteryTip> tips, BatteryInfo batteryInfo);
+ void addBatteryTipDetector(
+ Context context,
+ List<BatteryTip> batteryTips,
+ BatteryInfo batteryInfo,
+ BatteryTipPolicy batteryTipPolicy);
}
diff --git a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java
index f974b9d..f398373 100644
--- a/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java
+++ b/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImpl.java
@@ -18,6 +18,8 @@
import android.content.Context;
+import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
+import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import java.util.List;
@@ -42,5 +44,10 @@
@Override
public void addBatteryTipDetector(
- Context context, List<BatteryTip> tips, BatteryInfo batteryInfo) {}
+ Context context,
+ List<BatteryTip> batteryTips,
+ BatteryInfo batteryInfo,
+ BatteryTipPolicy batteryTipPolicy) {
+ batteryTips.add(new LowBatteryDetector(context, batteryTipPolicy, batteryInfo).detect());
+ }
}
diff --git a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsController.java b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsController.java
index 45c1be0..6425833 100644
--- a/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsController.java
+++ b/src/com/android/settings/fuelgauge/batterysaver/BatterySaverScheduleRadioButtonsController.java
@@ -41,7 +41,7 @@
public class BatterySaverScheduleRadioButtonsController {
private static final String TAG = "BatterySaverScheduleRadioButtonsController";
- public static final int TRIGGER_LEVEL_MIN = 10;
+ public static final int TRIGGER_LEVEL_MIN = 20;
private Context mContext;
private BatterySaverScheduleSeekBarController mSeekBarController;
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index 5352105..d68bf39 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.os.BatteryUsageStats;
-import android.os.PowerManager;
import androidx.annotation.VisibleForTesting;
@@ -27,7 +26,6 @@
import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector;
import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
import com.android.settings.fuelgauge.batterytip.detectors.IncompatibleChargerDetector;
-import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.utils.AsyncLoaderCompat;
@@ -56,19 +54,18 @@
@Override
public List<BatteryTip> loadInBackground() {
final List<BatteryTip> tips = new ArrayList<>();
- final BatteryTipPolicy policy = new BatteryTipPolicy(getContext());
+ final BatteryTipPolicy batteryTipPolicy = new BatteryTipPolicy(getContext());
final BatteryInfo batteryInfo = mBatteryUtils.getBatteryInfo(TAG);
final Context context = getContext().getApplicationContext();
- final boolean isPowerSaveMode =
- context.getSystemService(PowerManager.class).isPowerSaveMode();
- tips.add(new LowBatteryDetector(context, policy, batteryInfo, isPowerSaveMode).detect());
- tips.add(new HighUsageDetector(context, policy, mBatteryUsageStats, batteryInfo).detect());
+ tips.add(
+ new HighUsageDetector(context, batteryTipPolicy, mBatteryUsageStats, batteryInfo)
+ .detect());
tips.add(new BatteryDefenderDetector(batteryInfo, context).detect());
tips.add(new IncompatibleChargerDetector(context).detect());
FeatureFactory.getFeatureFactory()
.getBatterySettingsFeatureProvider()
- .addBatteryTipDetector(context, tips, batteryInfo);
+ .addBatteryTipDetector(context, tips, batteryInfo, batteryTipPolicy);
Collections.sort(tips);
return tips;
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java
index 1ce5a8e..b1a1562 100644
--- a/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetector.java
@@ -17,6 +17,7 @@
package com.android.settings.fuelgauge.batterytip.detectors;
import android.content.Context;
+import android.os.PowerManager;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
@@ -26,37 +27,33 @@
/** Detect whether the battery is too low */
public class LowBatteryDetector implements BatteryTipDetector {
private final BatteryInfo mBatteryInfo;
- private final BatteryTipPolicy mPolicy;
+ private final BatteryTipPolicy mBatteryTipPolicy;
private final boolean mIsPowerSaveMode;
private final int mWarningLevel;
public LowBatteryDetector(
- Context context,
- BatteryTipPolicy policy,
- BatteryInfo batteryInfo,
- boolean isPowerSaveMode) {
- mPolicy = policy;
+ Context context, BatteryTipPolicy batteryTipPolicy, BatteryInfo batteryInfo) {
+ mBatteryTipPolicy = batteryTipPolicy;
mBatteryInfo = batteryInfo;
mWarningLevel =
context.getResources()
.getInteger(com.android.internal.R.integer.config_lowBatteryWarningLevel);
- mIsPowerSaveMode = isPowerSaveMode;
+ mIsPowerSaveMode = context.getSystemService(PowerManager.class).isPowerSaveMode();
}
@Override
public BatteryTip detect() {
final boolean lowBattery = mBatteryInfo.batteryLevel <= mWarningLevel;
- final boolean lowBatteryEnabled = mPolicy.lowBatteryEnabled && !mIsPowerSaveMode;
+ final boolean lowBatteryEnabled = mBatteryTipPolicy.lowBatteryEnabled && !mIsPowerSaveMode;
final boolean dischargingLowBatteryState =
- mPolicy.testLowBatteryTip || (mBatteryInfo.discharging && lowBattery);
-
- int state = BatteryTip.StateType.INVISIBLE;
+ mBatteryTipPolicy.testLowBatteryTip || (mBatteryInfo.discharging && lowBattery);
// Show it as new if in test or in discharging low battery state,
// dismiss it if battery saver is on or disabled by config.
- if (lowBatteryEnabled && dischargingLowBatteryState) {
- state = BatteryTip.StateType.NEW;
- }
+ final int state =
+ lowBatteryEnabled && dischargingLowBatteryState
+ ? BatteryTip.StateType.NEW
+ : BatteryTip.StateType.INVISIBLE;
return new LowBatteryTip(state, mIsPowerSaveMode);
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
index 047bf13..319ba7a 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
@@ -16,12 +16,14 @@
package com.android.settings.fuelgauge.batterytip.tips;
+import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.os.Parcel;
import android.util.Log;
+import androidx.core.app.ActivityCompat;
import androidx.preference.Preference;
import com.android.settings.R;
@@ -30,6 +32,8 @@
import com.android.settingslib.HelpUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import kotlin.Unit;
+
/** Tip to show current battery is overheated */
public class BatteryDefenderTip extends BatteryTip {
@@ -83,28 +87,39 @@
}
cardPreference.setSelectable(false);
+ cardPreference.setIconResId(getIconId());
cardPreference.setPrimaryButtonText(context.getString(R.string.learn_more));
- cardPreference.setPrimaryButtonClickListener(
- button ->
- button.startActivityForResult(
- HelpUtils.getHelpIntent(
- context,
- context.getString(R.string.help_url_battery_defender),
- /* backupContext */ ""), /* requestCode */
- 0));
- cardPreference.setPrimaryButtonVisible(true);
+ cardPreference.setPrimaryButtonAction(
+ () -> {
+ var helpIntent =
+ HelpUtils.getHelpIntent(
+ context,
+ context.getString(R.string.help_url_battery_defender),
+ /* backupContext= */ "");
+ ActivityCompat.startActivityForResult(
+ (Activity) preference.getContext(),
+ helpIntent,
+ /* requestCode= */ 0,
+ /* options= */ null);
+
+ return Unit.INSTANCE;
+ });
+ cardPreference.setPrimaryButtonVisibility(true);
cardPreference.setPrimaryButtonContentDescription(
context.getString(
R.string.battery_tip_limited_temporarily_sec_button_content_description));
cardPreference.setSecondaryButtonText(
context.getString(R.string.battery_tip_charge_to_full_button));
- cardPreference.setSecondaryButtonClickListener(
- unused -> {
+ cardPreference.setSecondaryButtonAction(
+ () -> {
resumeCharging(context);
preference.setVisible(false);
+
+ return Unit.INSTANCE;
});
- cardPreference.setSecondaryButtonVisible(mIsPluggedIn);
+ cardPreference.setSecondaryButtonVisibility(mIsPluggedIn);
+ cardPreference.buildContent();
}
private void resumeCharging(Context context) {
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
index 882b755..c9ff864 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTip.java
@@ -16,11 +16,13 @@
package com.android.settings.fuelgauge.batterytip.tips;
+import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Parcel;
import android.util.Log;
+import androidx.core.app.ActivityCompat;
import androidx.preference.Preference;
import com.android.settings.R;
@@ -28,6 +30,8 @@
import com.android.settingslib.HelpUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import kotlin.Unit;
+
/** Tip to show incompatible charger state */
public final class IncompatibleChargerTip extends BatteryTip {
private static final String TAG = "IncompatibleChargerTip";
@@ -77,18 +81,27 @@
}
cardPreference.setSelectable(false);
+ cardPreference.setIconResId(getIconId());
cardPreference.setPrimaryButtonText(context.getString(R.string.learn_more));
- cardPreference.setPrimaryButtonClickListener(
- button ->
- button.startActivityForResult(
- HelpUtils.getHelpIntent(
- context,
- context.getString(R.string.help_url_incompatible_charging),
- /* backupContext */ ""), /* requestCode */
- 0));
- cardPreference.setPrimaryButtonVisible(true);
+ cardPreference.setPrimaryButtonAction(
+ () -> {
+ var helpIntent =
+ HelpUtils.getHelpIntent(
+ context,
+ context.getString(R.string.help_url_incompatible_charging),
+ /* backupContext */ "");
+ ActivityCompat.startActivityForResult(
+ (Activity) context,
+ helpIntent,
+ /* requestCode= */ 0,
+ /* options= */ null);
+
+ return Unit.INSTANCE;
+ });
+ cardPreference.setPrimaryButtonVisibility(true);
cardPreference.setPrimaryButtonContentDescription(
context.getString(R.string.battery_tip_incompatible_charging_content_description));
+ cardPreference.buildContent();
}
public static final Creator CREATOR =
diff --git a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
index c6b1bdb..c40212b 100644
--- a/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
+++ b/src/com/android/settings/gestures/SystemNavigationGestureSettings.java
@@ -41,7 +41,6 @@
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceScreen;
-import com.android.internal.accessibility.common.ShortcutConstants;
import com.android.settings.R;
import com.android.settings.accessibility.AccessibilityGestureNavigationTutorial;
import com.android.settings.core.SubSettingLauncher;
@@ -354,7 +353,7 @@
private boolean isAnyServiceSupportAccessibilityButton() {
final AccessibilityManager ams = getContext().getSystemService(AccessibilityManager.class);
final List<String> targets = ams.getAccessibilityShortcutTargets(
- ShortcutConstants.UserShortcutType.SOFTWARE);
+ AccessibilityManager.ACCESSIBILITY_BUTTON);
return !targets.isEmpty();
}
diff --git a/src/com/android/settings/notification/PoliteNotifWorkProfileToggleController.java b/src/com/android/settings/notification/PoliteNotifWorkProfileToggleController.java
index 65b4fb8..99d0a69 100644
--- a/src/com/android/settings/notification/PoliteNotifWorkProfileToggleController.java
+++ b/src/com/android/settings/notification/PoliteNotifWorkProfileToggleController.java
@@ -62,7 +62,7 @@
@Override
public boolean isChecked() {
return Settings.System.getIntForUser(mContext.getContentResolver(),
- Settings.System.NOTIFICATION_COOLDOWN_ENABLED, OFF, mManagedProfileId) != OFF;
+ Settings.System.NOTIFICATION_COOLDOWN_ENABLED, ON, mManagedProfileId) != OFF;
}
@Override
diff --git a/src/com/android/settings/spa/app/appinfo/AppButtons.kt b/src/com/android/settings/spa/app/appinfo/AppButtons.kt
index dcce1d9..3d9c4b1 100644
--- a/src/com/android/settings/spa/app/appinfo/AppButtons.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppButtons.kt
@@ -17,8 +17,8 @@
package com.android.settings.spa.app.appinfo
import android.content.pm.ApplicationInfo
-import android.content.pm.FeatureFlags
-import android.content.pm.FeatureFlagsImpl
+import android.content.pm.FeatureFlags as PmFeatureFlags
+import android.content.pm.FeatureFlagsImpl as PmFeatureFlagsImpl
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@@ -34,7 +34,7 @@
fun AppButtons(
packageInfoPresenter: PackageInfoPresenter,
isHibernationSwitchEnabledStateFlow: MutableStateFlow<Boolean>,
- featureFlags: FeatureFlags = FeatureFlagsImpl()
+ featureFlags: PmFeatureFlags = PmFeatureFlagsImpl()
) {
if (remember(packageInfoPresenter) { packageInfoPresenter.isMainlineModule() }) return
val presenter = remember {
@@ -53,7 +53,7 @@
private class AppButtonsPresenter(
private val packageInfoPresenter: PackageInfoPresenter,
isHibernationSwitchEnabledStateFlow: MutableStateFlow<Boolean>,
- private val featureFlags: FeatureFlags
+ private val featureFlags: PmFeatureFlags
) {
private val appLaunchButton = AppLaunchButton(packageInfoPresenter)
private val appInstallButton = AppInstallButton(packageInfoPresenter)
diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
index dba6184..695e114 100644
--- a/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
+++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettings.kt
@@ -18,9 +18,8 @@
import android.app.settings.SettingsEnums
import android.content.pm.ApplicationInfo
-import android.content.pm.FeatureFlags
-import android.content.pm.FeatureFlagsImpl
import android.os.Bundle
+import android.os.SystemProperties
import android.os.UserHandle
import android.util.FeatureFlagUtils
import androidx.compose.runtime.Composable
@@ -51,6 +50,8 @@
import com.android.settingslib.spaprivileged.model.app.toRoute
import com.android.settingslib.spaprivileged.template.app.AppInfoProvider
import kotlinx.coroutines.flow.MutableStateFlow
+import android.content.pm.FeatureFlags as PmFeatureFlags
+import android.content.pm.FeatureFlagsImpl as PmFeatureFlagsImpl
private const val PACKAGE_NAME = "packageName"
private const val USER_ID = "userId"
@@ -121,7 +122,7 @@
@Composable
private fun AppInfoSettings(packageInfoPresenter: PackageInfoPresenter) {
val packageInfoState = packageInfoPresenter.flow.collectAsStateWithLifecycle()
- val featureFlags: FeatureFlags = FeatureFlagsImpl()
+ val featureFlags: PmFeatureFlags = PmFeatureFlagsImpl()
RegularScaffold(
title = stringResource(R.string.application_info_label),
actions = {
@@ -177,5 +178,6 @@
}
}
-fun isArchivingEnabled(featureFlags: FeatureFlags) =
- featureFlags.archiving() || "true" == System.getProperty("pm.archiving.enabled")
+fun isArchivingEnabled(featureFlags: PmFeatureFlags) =
+ featureFlags.archiving() || SystemProperties.getBoolean("pm.archiving.enabled", false)
+ || Flags.appArchiving()
\ No newline at end of file
diff --git a/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt b/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt
index 4f47266..86d7f44 100644
--- a/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt
+++ b/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreference.kt
@@ -22,8 +22,9 @@
import android.app.AppOpsManager.OP_AUTO_REVOKE_PERMISSIONS_IF_UNUSED
import android.content.Context
import android.content.pm.ApplicationInfo
-import android.content.pm.Flags
+import android.content.pm.Flags as PmFlags
import android.os.Build
+import android.os.SystemProperties
import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_EXEMPT_BY_SYSTEM
import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_UNKNOWN
import android.provider.DeviceConfig
@@ -36,6 +37,7 @@
import com.android.settings.R
import com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED
import com.android.settings.Utils.PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS
+import com.android.settings.flags.Flags
import com.android.settingslib.spa.framework.compose.OverridableFlow
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
@@ -91,7 +93,8 @@
}
private fun isArchivingEnabled() =
- Flags.archiving() || "true" == System.getProperty("pm.archiving.enabled")
+ PmFlags.archiving() || SystemProperties.getBoolean("pm.archiving.enabled", false)
+ || Flags.appArchiving()
private class HibernationSwitchPresenter(context: Context, private val app: ApplicationInfo) {
private val appOpsManager = context.appOpsManager
diff --git a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
index 230ccb9..81abae5 100644
--- a/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
+++ b/src/com/android/settings/spa/app/appinfo/PackageInfoPresenter.kt
@@ -20,14 +20,16 @@
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
-import android.content.pm.FeatureFlags
-import android.content.pm.FeatureFlagsImpl
+import android.content.pm.FeatureFlags as PmFeatureFlags
+import android.content.pm.FeatureFlagsImpl as PmFeatureFlagsImpl
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.os.UserHandle
import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.compose.runtime.Composable
+import com.android.settings.flags.FeatureFlags
+import com.android.settings.flags.FeatureFlagsImpl
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settings.spa.app.startUninstallActivity
import com.android.settingslib.spa.framework.compose.LocalNavController
@@ -60,7 +62,7 @@
val userId: Int,
private val coroutineScope: CoroutineScope,
private val packageManagers: IPackageManagers = PackageManagers,
- private val featureFlags: FeatureFlags = FeatureFlagsImpl(),
+ private val featureFlags: PmFeatureFlags = PmFeatureFlagsImpl(),
) {
private val metricsFeatureProvider = featureFactory.metricsFeatureProvider
private val userHandle = UserHandle.of(userId)
diff --git a/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt b/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt
index 3e48aa5..2b8d12d 100644
--- a/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt
+++ b/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt
@@ -27,7 +27,8 @@
import androidx.compose.runtime.Composable
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settingslib.R
-import com.android.settingslib.spa.livedata.observeAsCallback
+import com.android.settingslib.spa.lifecycle.collectAsCallbackWithLifecycle
+import com.android.settingslib.spaprivileged.model.app.AppOpsController
import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
import com.android.settingslib.spaprivileged.model.app.PackageManagers
@@ -47,7 +48,7 @@
override val app: ApplicationInfo,
val isTrumped: Boolean,
val isChangeable: Boolean,
- var controller: AlarmsAndRemindersController,
+ var controller: AppOpsController,
) : AppRecord
class AlarmsAndRemindersAppListModel(
@@ -82,7 +83,7 @@
@Composable
override fun isAllowed(record: AlarmsAndRemindersAppRecord): () -> Boolean? = when {
record.isTrumped -> ({ true })
- else -> record.controller.isAllowed.observeAsCallback()
+ else -> record.controller.isAllowed.collectAsCallbackWithLifecycle()
}
override fun isChangeable(record: AlarmsAndRemindersAppRecord) = record.isChangeable
@@ -112,7 +113,12 @@
app = app,
isTrumped = isTrumped,
isChangeable = hasRequestPermission && !isTrumped,
- controller = AlarmsAndRemindersController(context, app),
+ controller = AppOpsController(
+ context = context,
+ app = app,
+ op = AppOpsManager.OP_SCHEDULE_EXACT_ALARM,
+ setModeByUid = true,
+ ),
)
}
diff --git a/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersController.kt b/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersController.kt
deleted file mode 100644
index bd40f45..0000000
--- a/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersController.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.spa.app.specialaccess
-
-import android.app.AppOpsManager
-import android.app.AppOpsManager.MODE_ALLOWED
-import android.app.AppOpsManager.MODE_ERRORED
-import android.content.Context
-import android.content.pm.ApplicationInfo
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import com.android.settingslib.spaprivileged.framework.common.alarmManager
-import com.android.settingslib.spaprivileged.framework.common.appOpsManager
-import com.android.settingslib.spaprivileged.model.app.userId
-
-class AlarmsAndRemindersController(
- context: Context,
- private val app: ApplicationInfo,
-) {
- private val alarmManager = context.alarmManager
- private val appOpsManager = context.appOpsManager
-
- val isAllowed: LiveData<Boolean>
- get() = _allowed
-
- fun setAllowed(allowed: Boolean) {
- val mode = if (allowed) MODE_ALLOWED else MODE_ERRORED
- appOpsManager.setUidMode(AppOpsManager.OP_SCHEDULE_EXACT_ALARM, app.uid, mode)
- _allowed.postValue(allowed)
- }
-
- private val _allowed = object : MutableLiveData<Boolean>() {
- override fun onActive() {
- postValue(alarmManager.hasScheduleExactAlarm(app.packageName, app.userId))
- }
- }
-}
diff --git a/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
index dc98330..3e9058f 100644
--- a/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
+++ b/src/com/android/settings/spa/app/specialaccess/InstallUnknownApps.kt
@@ -26,7 +26,7 @@
import android.os.UserManager
import androidx.compose.runtime.Composable
import com.android.settings.R
-import com.android.settingslib.spa.livedata.observeAsCallback
+import com.android.settingslib.spa.lifecycle.collectAsCallbackWithLifecycle
import com.android.settingslib.spaprivileged.model.app.AppOpsController
import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.userId
@@ -81,7 +81,7 @@
@Composable
override fun isAllowed(record: InstallUnknownAppsRecord) =
- record.appOpsController.isAllowed.observeAsCallback()
+ record.appOpsController.isAllowed.collectAsCallbackWithLifecycle()
override fun isChangeable(record: InstallUnknownAppsRecord) =
isChangeable(record, getPotentialPackageNames(record.app.userId))
diff --git a/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt b/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
index fe8f103..7885b86 100644
--- a/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
+++ b/src/com/android/settings/spa/app/specialaccess/PictureInPicture.kt
@@ -27,7 +27,7 @@
import android.util.Log
import androidx.compose.runtime.Composable
import com.android.settings.R
-import com.android.settingslib.spa.livedata.observeAsCallback
+import com.android.settingslib.spa.lifecycle.collectAsCallbackWithLifecycle
import com.android.settingslib.spaprivileged.model.app.AppOpsController
import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.installed
@@ -92,7 +92,7 @@
@Composable
override fun isAllowed(record: PictureInPictureRecord) =
- record.appOpsController.isAllowed.observeAsCallback()
+ record.appOpsController.isAllowed.collectAsCallbackWithLifecycle()
override fun isChangeable(record: PictureInPictureRecord) = record.isSupport
diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java
index a758e34..a030d86 100644
--- a/src/com/android/settings/users/UserDetailsSettings.java
+++ b/src/com/android/settings/users/UserDetailsSettings.java
@@ -476,9 +476,12 @@
private void enableCallsAndSms(boolean enabled) {
mPhonePref.setChecked(enabled);
- UserHandle userHandle = UserHandle.of(mUserInfo.id);
- mUserManager.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, !enabled, userHandle);
- mUserManager.setUserRestriction(UserManager.DISALLOW_SMS, !enabled, userHandle);
+ int[] userProfiles = mUserManager.getProfileIdsWithDisabled(mUserInfo.id);
+ for (int userId : userProfiles) {
+ UserHandle user = UserHandle.of(userId);
+ mUserManager.setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, !enabled, user);
+ mUserManager.setUserRestriction(UserManager.DISALLOW_SMS, !enabled, user);
+ }
}
/**
diff --git a/src/com/android/settings/widget/CardPreference.java b/src/com/android/settings/widget/CardPreference.java
deleted file mode 100644
index 61114d9..0000000
--- a/src/com/android/settings/widget/CardPreference.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.Button;
-
-import androidx.preference.Preference;
-import androidx.preference.PreferenceViewHolder;
-
-import com.android.settings.R;
-
-import com.google.android.material.card.MaterialCardView;
-
-import java.util.Optional;
-
-/** Preference that wrapped by {@link MaterialCardView} */
-public class CardPreference extends Preference {
-
- private View.OnClickListener mPrimaryBtnClickListener = null;
- private View.OnClickListener mSecondaryBtnClickListener = null;
-
- private String mPrimaryButtonText = null;
- private String mSecondaryButtonText = null;
-
- private Optional<Button> mPrimaryButton = Optional.empty();
- private Optional<Button> mSecondaryButton = Optional.empty();
- private Optional<View> mButtonsGroup = Optional.empty();
-
- private boolean mPrimaryButtonVisible = false;
- private boolean mSecondaryButtonVisible = false;
-
- public CardPreference(Context context) {
- this(context, null /* attrs */);
- }
-
- public CardPreference(Context context, AttributeSet attrs) {
- super(context, attrs, R.attr.cardPreferenceStyle);
- }
-
- @Override
- public void onBindViewHolder(PreferenceViewHolder holder) {
- super.onBindViewHolder(holder);
-
- initButtonsAndLayout(holder);
- }
-
- private void initButtonsAndLayout(PreferenceViewHolder holder) {
- mPrimaryButton = Optional.ofNullable((Button) holder.findViewById(android.R.id.button1));
- mSecondaryButton = Optional.ofNullable((Button) holder.findViewById(android.R.id.button2));
- mButtonsGroup = Optional.ofNullable(holder.findViewById(R.id.card_preference_buttons));
-
- setPrimaryButtonText(mPrimaryButtonText);
- setPrimaryButtonClickListener(mPrimaryBtnClickListener);
- setPrimaryButtonVisible(mPrimaryButtonVisible);
- setSecondaryButtonText(mSecondaryButtonText);
- setSecondaryButtonClickListener(mSecondaryBtnClickListener);
- setSecondaryButtonVisible(mSecondaryButtonVisible);
- }
-
- /** Clear layout state if needed */
- public void resetLayoutState() {
- setPrimaryButtonVisible(false);
- setSecondaryButtonVisible(false);
- }
-
- /**
- * Register a callback to be invoked when the primary button is clicked.
- *
- * @param l the callback that will run
- */
- public void setPrimaryButtonClickListener(View.OnClickListener l) {
- mPrimaryButton.ifPresent(button -> button.setOnClickListener(l));
- mPrimaryBtnClickListener = l;
- }
-
- /**
- * Register a callback to be invoked when the secondary button is clicked.
- *
- * @param l the callback that will run
- */
- public void setSecondaryButtonClickListener(View.OnClickListener l) {
- mSecondaryButton.ifPresent(button -> button.setOnClickListener(l));
- mSecondaryBtnClickListener = l;
- }
-
- /**
- * Sets the text to be displayed on primary button.
- *
- * @param text text to be displayed
- */
- public void setPrimaryButtonText(String text) {
- mPrimaryButton.ifPresent(button -> button.setText(text));
- mPrimaryButtonText = text;
- }
-
- /**
- * Sets the text to be displayed on secondary button.
- *
- * @param text text to be displayed
- */
- public void setSecondaryButtonText(String text) {
- mSecondaryButton.ifPresent(button -> button.setText(text));
- mSecondaryButtonText = text;
- }
-
- /**
- * Set the visible on the primary button.
- *
- * @param visible {@code true} for visible
- */
- public void setPrimaryButtonVisible(boolean visible) {
- mPrimaryButton.ifPresent(
- button -> button.setVisibility(visible ? View.VISIBLE : View.GONE));
- mPrimaryButtonVisible = visible;
- updateButtonGroupsVisibility();
- }
-
- /**
- * Set the visible on the secondary button.
- *
- * @param visible {@code true} for visible
- */
- public void setSecondaryButtonVisible(boolean visible) {
- mSecondaryButton.ifPresent(
- button -> button.setVisibility(visible ? View.VISIBLE : View.GONE));
- mSecondaryButtonVisible = visible;
- updateButtonGroupsVisibility();
- }
-
- /**
- * Sets the text of content description on primary button.
- *
- * @param text text for the content description
- */
- public void setPrimaryButtonContentDescription(String text) {
- mPrimaryButton.ifPresent(button -> button.setContentDescription(text));
- }
-
- /**
- * Sets the text of content description on secondary button.
- *
- * @param text text for the content description
- */
- public void setSecondaryButtonContentDescription(String text) {
- mSecondaryButton.ifPresent(button -> button.setContentDescription(text));
- }
-
- private void updateButtonGroupsVisibility() {
- int visibility =
- (mPrimaryButtonVisible || mSecondaryButtonVisible) ? View.VISIBLE : View.GONE;
- mButtonsGroup.ifPresent(group -> group.setVisibility(visibility));
- }
-}
diff --git a/src/com/android/settings/widget/CardPreference.kt b/src/com/android/settings/widget/CardPreference.kt
new file mode 100644
index 0000000..7122ac6
--- /dev/null
+++ b/src/com/android/settings/widget/CardPreference.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.widget
+
+import android.content.Context
+import android.content.res.Resources
+import android.util.AttributeSet
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.vectorResource
+import com.android.settings.spa.preference.ComposePreference
+import com.android.settingslib.spa.widget.card.CardButton
+import com.android.settingslib.spa.widget.card.CardModel
+import com.android.settingslib.spa.widget.card.SettingsCard
+
+/** A preference for settings banner tips card. */
+class CardPreference
+@JvmOverloads
+constructor(
+ context: Context,
+ attr: AttributeSet? = null,
+) : ComposePreference(context, attr) {
+
+ /** A icon resource id for displaying icon on tips card. */
+ var iconResId: Int? = null
+
+ /** The primary button's text. */
+ var primaryButtonText: String = ""
+
+ /** The accessibility content description of the primary button. */
+ var primaryButtonContentDescription: String? = null
+
+ /** The action for click on primary button. */
+ var primaryButtonAction: () -> Unit = {}
+
+ /** The visibility of primary button on tips card. The default value is `false`. */
+ var primaryButtonVisibility: Boolean = false
+
+ /** The text on the second button of this [SettingsCard]. */
+ var secondaryButtonText: String = ""
+
+ /** The accessibility content description of the secondary button. */
+ var secondaryButtonContentDescription: String? = null
+
+ /** The action for click on secondary button. */
+ var secondaryButtonAction: () -> Unit = {}
+
+ /** The visibility of secondary button on tips card. The default value is `false`. */
+ var secondaryButtonVisibility: Boolean = false
+
+ private var onDismiss: (() -> Unit)? = null
+
+ /** Enable the dismiss button on tips card. */
+ fun enableDismiss(enable: Boolean) =
+ if (enable) onDismiss = { isVisible = false } else onDismiss = null
+
+ /** Clear layout state if needed. */
+ fun resetLayoutState() {
+ primaryButtonVisibility = false
+ secondaryButtonVisibility = false
+ notifyChanged()
+ }
+
+ /** Build the tips card content to apply any changes of this card's property. */
+ fun buildContent() {
+ setContent {
+ SettingsCard(
+ CardModel(
+ title = title?.toString() ?: "",
+ text = summary?.toString() ?: "",
+ buttons = listOfNotNull(configPrimaryButton(), configSecondaryButton()),
+ onDismiss = onDismiss,
+ imageVector =
+ iconResId
+ ?.takeIf { it != Resources.ID_NULL }
+ ?.let { ImageVector.vectorResource(it) },
+ )
+ )
+ }
+ }
+
+ private fun configPrimaryButton(): CardButton? {
+ return if (primaryButtonVisibility)
+ CardButton(
+ text = primaryButtonText,
+ contentDescription = primaryButtonContentDescription,
+ onClick = primaryButtonAction,
+ )
+ else null
+ }
+
+ private fun configSecondaryButton(): CardButton? {
+ return if (secondaryButtonVisibility)
+ CardButton(
+ text = secondaryButtonText,
+ contentDescription = secondaryButtonContentDescription,
+ onClick = secondaryButtonAction,
+ )
+ else null
+ }
+
+ override fun notifyChanged() {
+ buildContent()
+ super.notifyChanged()
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiScanModeActivity.java b/src/com/android/settings/wifi/WifiScanModeActivity.java
index c10ee27..446891a 100644
--- a/src/com/android/settings/wifi/WifiScanModeActivity.java
+++ b/src/com/android/settings/wifi/WifiScanModeActivity.java
@@ -39,26 +39,24 @@
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settingslib.wifi.WifiPermissionChecker;
-/**
- * This activity requests users permission to allow scanning even when Wi-Fi is turned off
- */
+/** This activity requests users permission to allow scanning even when Wi-Fi is turned off */
public class WifiScanModeActivity extends FragmentActivity {
private static final String TAG = "WifiScanModeActivity";
private DialogFragment mDialog;
- @VisibleForTesting
- String mApp;
- @VisibleForTesting
- WifiPermissionChecker mWifiPermissionChecker;
+ @VisibleForTesting String mApp;
+ @VisibleForTesting WifiPermissionChecker mWifiPermissionChecker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- getWindow().addSystemFlags(
- WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+ getWindow()
+ .addSystemFlags(
+ WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
Intent intent = getIntent();
if (savedInstanceState == null) {
- if (intent != null && WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
- .equals(intent.getAction())) {
+ if (intent != null
+ && WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE.equals(
+ intent.getAction())) {
refreshAppLabel();
} else {
finish();
@@ -92,6 +90,12 @@
return;
}
+ if (!isWifiScanModeConfigAllowed(getApplicationContext())) {
+ Log.e(TAG, "This user is not allowed to configure Wi-Fi Scan Mode!");
+ finish();
+ return;
+ }
+
if (mDialog == null) {
mDialog = AlertDialogFragment.newInstance(mApp);
mDialog.show(getSupportFragmentManager(), "dialog");
@@ -140,6 +144,7 @@
}
private final String mApp;
+
public AlertDialogFragment(String app) {
super();
mApp = app;
@@ -158,25 +163,27 @@
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
- .setMessage(TextUtils.isEmpty(mApp) ?
- getString(R.string.wifi_scan_always_turn_on_message_unknown) :
- getString(R.string.wifi_scan_always_turnon_message, mApp))
- .setPositiveButton(R.string.wifi_scan_always_confirm_allow,
+ .setMessage(
+ TextUtils.isEmpty(mApp)
+ ? getString(R.string.wifi_scan_always_turn_on_message_unknown)
+ : getString(R.string.wifi_scan_always_turnon_message, mApp))
+ .setPositiveButton(
+ R.string.wifi_scan_always_confirm_allow,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
((WifiScanModeActivity) getActivity()).doPositiveClick();
}
- }
- )
- .setNegativeButton(R.string.wifi_scan_always_confirm_deny,
+ })
+ .setNegativeButton(
+ R.string.wifi_scan_always_confirm_deny,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
((WifiScanModeActivity) getActivity()).doNegativeClick();
}
- }
- )
+ })
.create();
}
+
@Override
public void onCancel(DialogInterface dialog) {
((WifiScanModeActivity) getActivity()).doNegativeClick();
@@ -184,9 +191,14 @@
}
private static boolean isGuestUser(Context context) {
- if (context == null) return false;
final UserManager userManager = context.getSystemService(UserManager.class);
if (userManager == null) return false;
return userManager.isGuestUser();
}
+
+ private static boolean isWifiScanModeConfigAllowed(Context context) {
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ if (userManager == null) return true;
+ return !userManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_LOCATION);
+ }
}
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
index a90d627..82537d4 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
@@ -27,6 +27,7 @@
import android.os.Bundle;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
+import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
@@ -49,6 +50,7 @@
import com.android.ims.ImsConfig;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.flags.Flags;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
@@ -97,6 +99,7 @@
private boolean mEditableWfcMode = true;
private boolean mEditableWfcRoamingMode = true;
private boolean mUseWfcHomeModeForRoaming = false;
+ private boolean mOverrideWfcRoamingModeWhileUsingNtn = false;
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private ImsMmTelManager mImsMmTelManager;
@@ -166,7 +169,8 @@
final Preference pref_roam =
getPreferenceScreen().findPreference(BUTTON_WFC_ROAMING_MODE);
if (pref_roam != null) {
- pref_roam.setEnabled(isWfcRoamingModeEditable);
+ pref_roam.setEnabled(isWfcRoamingModeEditable
+ && !overrideWfcRoamingModeWhileUsingNtn());
}
}
}
@@ -361,6 +365,9 @@
false);
isWifiOnlySupported = b.getBoolean(
CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true);
+ mOverrideWfcRoamingModeWhileUsingNtn = b.getBoolean(
+ CarrierConfigManager.KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL,
+ true);
}
}
@@ -577,7 +584,8 @@
mButtonWfcMode.setSummary(getWfcModeSummary(wfcMode));
mButtonWfcMode.setEnabled(wfcEnabled && mEditableWfcMode);
// mButtonWfcRoamingMode.setSummary is not needed; summary is just selected value.
- mButtonWfcRoamingMode.setEnabled(wfcEnabled && mEditableWfcRoamingMode);
+ mButtonWfcRoamingMode.setEnabled(wfcEnabled && mEditableWfcRoamingMode
+ && !overrideWfcRoamingModeWhileUsingNtn());
final PreferenceScreen preferenceScreen = getPreferenceScreen();
final boolean updateAddressEnabled = (getCarrierActivityIntent() != null);
@@ -711,4 +719,30 @@
}
mProvisioningManager.unregisterProvisioningChangedCallback(mProvisioningCallback);
}
+
+ /**
+ * Determine whether to override roaming Wi-Fi calling preference when device is connected to
+ * non-terrestrial network.
+ *
+ * @return {@code true} if phone is connected to non-terrestrial network and if
+ * {@link CarrierConfigManager#KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL} is true,
+ * {@code false} otherwise.
+ */
+ private boolean overrideWfcRoamingModeWhileUsingNtn() {
+ if (!Flags.carrierEnabledSatelliteFlag()) {
+ return false;
+ }
+
+ TelephonyManager tm = getTelephonyManagerForSub(mSubId);
+ ServiceState serviceState = tm.getServiceState();
+ if (serviceState == null) {
+ return false;
+ }
+
+ if (!serviceState.isUsingNonTerrestrialNetwork()) {
+ return false;
+ }
+
+ return mOverrideWfcRoamingModeWhileUsingNtn;
+ }
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
index cfd256f..fc72c41 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragmentTest.java
@@ -18,6 +18,8 @@
import static android.bluetooth.BluetoothDevice.BOND_NONE;
+import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceControlsController.KEY_DEVICE_CONTROLS_GENERAL_GROUP;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
@@ -29,8 +31,10 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.settings.SettingsEnums;
import android.companion.CompanionDeviceManager;
import android.content.Context;
+import android.content.Intent;
import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.UserManager;
@@ -49,6 +53,8 @@
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.google.common.collect.ImmutableList;
@@ -65,6 +71,8 @@
import org.robolectric.annotation.Config;
import org.robolectric.fakes.RoboMenu;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
com.android.settings.testutils.shadow.ShadowUserManager.class,
@@ -216,6 +224,38 @@
verify(mFragment).finish();
}
+ @Test
+ public void createPreferenceControllers_launchFromHAPage_deviceControllerNotExist() {
+ BluetoothDeviceDetailsFragment fragment = setupFragment();
+ Intent intent = fragment.getActivity().getIntent();
+ intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
+ SettingsEnums.ACCESSIBILITY_HEARING_AID_SETTINGS);
+ fragment.onAttach(mContext);
+
+ List<AbstractPreferenceController> controllerList = fragment.createPreferenceControllers(
+ mContext);
+
+ assertThat(controllerList.stream()
+ .anyMatch(controller -> controller.getPreferenceKey().equals(
+ KEY_DEVICE_CONTROLS_GENERAL_GROUP))).isFalse();
+ }
+
+ @Test
+ public void createPreferenceControllers_notLaunchFromHAPage_deviceControllerExist() {
+ BluetoothDeviceDetailsFragment fragment = setupFragment();
+ Intent intent = fragment.getActivity().getIntent();
+ intent.putExtra(MetricsFeatureProvider.EXTRA_SOURCE_METRICS_CATEGORY,
+ SettingsEnums.PAGE_UNKNOWN);
+ fragment.onAttach(mContext);
+
+ List<AbstractPreferenceController> controllerList = fragment.createPreferenceControllers(
+ mContext);
+
+ assertThat(controllerList.stream()
+ .anyMatch(controller -> controller.getPreferenceKey().equals(
+ KEY_DEVICE_CONTROLS_GENERAL_GROUP))).isTrue();
+ }
+
private InputDevice createInputDeviceWithMatchingBluetoothAddress() {
doReturn(new int[]{0}).when(mInputManager).getInputDeviceIds();
InputDevice device = mock(InputDevice.class);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
index 00115d7..cd48bf1 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
@@ -20,6 +20,8 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -28,18 +30,26 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Pair;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowAudioManager;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowCachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -58,6 +68,10 @@
public class ConnectedBluetoothDeviceUpdaterTest {
private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
+ private static final String FAKE_EXCLUSIVE_MANAGER_NAME = "com.fake.name";
+
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private DashboardFragment mDashboardFragment;
@@ -69,6 +83,8 @@
private BluetoothDevice mBluetoothDevice;
@Mock
private Drawable mDrawable;
+ @Mock
+ private PackageManager mPackageManager;
private Context mContext;
private ConnectedBluetoothDeviceUpdater mBluetoothDeviceUpdater;
@@ -82,7 +98,7 @@
MockitoAnnotations.initMocks(this);
Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device");
- mContext = RuntimeEnvironment.application;
+ mContext = spy(RuntimeEnvironment.application);
mAudioManager = mContext.getSystemService(AudioManager.class);
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
mShadowBluetoothAdapter.setEnabled(true);
@@ -92,6 +108,7 @@
mCachedDevices = new ArrayList<>();
mCachedDevices.add(mCachedBluetoothDevice);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS);
when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pairs);
@@ -320,4 +337,97 @@
assertThat(btPreference.shouldHideSecondTarget()).isTrue();
}
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+ public void update_notExclusiveManagedDevice_addDevice() {
+ mAudioManager.setMode(AudioManager.MODE_NORMAL);
+ when(mBluetoothDeviceUpdater
+ .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+ null);
+
+ mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+ verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+ public void update_notAllowedExclusiveManagedDevice_addDevice() {
+ mAudioManager.setMode(AudioManager.MODE_NORMAL);
+ when(mBluetoothDeviceUpdater
+ .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+ FAKE_EXCLUSIVE_MANAGER_NAME.getBytes());
+
+ mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+ verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+ public void update_existingExclusivelyManagedDeviceWithPackageInstalled_removePreference()
+ throws Exception {
+ final String exclusiveManagerName =
+ BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
+ FAKE_EXCLUSIVE_MANAGER_NAME);
+ mAudioManager.setMode(AudioManager.MODE_NORMAL);
+ when(mBluetoothDeviceUpdater
+ .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+ exclusiveManagerName.getBytes());
+ doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0);
+
+ mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+ verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+ verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+ public void update_newExclusivelyManagedDeviceWithPackageInstalled_doNotAddPreference()
+ throws Exception {
+ final String exclusiveManagerName =
+ BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
+ FAKE_EXCLUSIVE_MANAGER_NAME);
+ mAudioManager.setMode(AudioManager.MODE_NORMAL);
+ when(mBluetoothDeviceUpdater
+ .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+ exclusiveManagerName.getBytes());
+ doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0);
+
+ mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+ verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+ verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+ public void update_exclusivelyManagedDeviceWithoutPackageInstalled_addDevice()
+ throws Exception {
+ final String exclusiveManagerName =
+ BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
+ FAKE_EXCLUSIVE_MANAGER_NAME);
+ mAudioManager.setMode(AudioManager.MODE_NORMAL);
+ when(mBluetoothDeviceUpdater
+ .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+ when(mCachedBluetoothDevice.isConnectedHfpDevice()).thenReturn(true);
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+ exclusiveManagerName.getBytes());
+ doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager).getPackageInfo(
+ exclusiveManagerName, 0);
+
+ mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+ verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java
index c229449..349391d 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdaterTest.java
@@ -18,6 +18,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -28,17 +29,26 @@
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
+import android.platform.test.annotations.RequiresFlagsDisabled;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.Pair;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
+import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -56,6 +66,10 @@
public class SavedBluetoothDeviceUpdaterTest {
private static final String MAC_ADDRESS = "04:52:C7:0B:D8:3C";
+ private static final String FAKE_EXCLUSIVE_MANAGER_NAME = "com.fake.name";
+
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private DashboardFragment mDashboardFragment;
@@ -73,6 +87,8 @@
private LocalBluetoothManager mBluetoothManager;
@Mock
private Drawable mDrawable;
+ @Mock
+ private PackageManager mPackageManager;
private Context mContext;
private SavedBluetoothDeviceUpdater mBluetoothDeviceUpdater;
@@ -84,12 +100,13 @@
MockitoAnnotations.initMocks(this);
Pair<Drawable, String> pairs = new Pair<>(mDrawable, "fake_device");
- mContext = RuntimeEnvironment.application;
+ mContext = spy(RuntimeEnvironment.application);
doReturn(mContext).when(mDashboardFragment).getContext();
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
when(mCachedBluetoothDevice.getAddress()).thenReturn(MAC_ADDRESS);
when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
when(mCachedBluetoothDevice.getDrawableWithDescription()).thenReturn(pairs);
+ when(mContext.getPackageManager()).thenReturn(mPackageManager);
mBluetoothDeviceUpdater = spy(new SavedBluetoothDeviceUpdater(mContext,
mDevicePreferenceCallback, false, /* metricsCategory= */ 0));
@@ -103,10 +120,10 @@
mCachedDevices.add(mCachedBluetoothDevice);
when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
when(mDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices);
-
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_filterMatch_addPreference() {
doReturn(BluetoothDevice.BOND_BONDED).when(mBluetoothDevice).getBondState();
doReturn(false).when(mBluetoothDevice).isConnected();
@@ -118,6 +135,7 @@
}
@Test
+ @RequiresFlagsDisabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
public void update_filterNotMatch_removePreference() {
doReturn(BluetoothDevice.BOND_NONE).when(mBluetoothDevice).getBondState();
doReturn(true).when(mBluetoothDevice).isConnected();
@@ -298,4 +316,125 @@
verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice,
BluetoothDevicePreference.SortType.TYPE_NO_SORT);
}
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+ public void update_notExclusivelyManagedDevice_addDevice() {
+ final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+ cachedDevices.add(mCachedBluetoothDevice);
+
+ when(mBluetoothAdapter.isEnabled()).thenReturn(true);
+ when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
+ when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+ when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mBluetoothDevice.isConnected()).thenReturn(false);
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+ null);
+
+ mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+ verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice,
+ BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+ public void update_notAllowedExclusivelyManagedDevice_addDevice() {
+ final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+ cachedDevices.add(mCachedBluetoothDevice);
+
+ when(mBluetoothAdapter.isEnabled()).thenReturn(true);
+ when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
+ when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+ when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mBluetoothDevice.isConnected()).thenReturn(false);
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+ FAKE_EXCLUSIVE_MANAGER_NAME.getBytes());
+
+ mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+ verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice,
+ BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+ public void update_existingExclusivelyManagedDeviceWithPackageInstalled_removePreference()
+ throws Exception {
+ final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+ final String exclusiveManagerName =
+ BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
+ FAKE_EXCLUSIVE_MANAGER_NAME);
+
+ when(mBluetoothAdapter.isEnabled()).thenReturn(true);
+ when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
+ when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+ when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mBluetoothDevice.isConnected()).thenReturn(false);
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+ exclusiveManagerName.getBytes());
+
+ doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0);
+ mBluetoothDeviceUpdater.mPreferenceMap.put(mBluetoothDevice, mPreference);
+
+ mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+ verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+ verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice,
+ BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+ public void update_newExclusivelyManagedDeviceWithPackageInstalled_doNotAddPreference()
+ throws Exception {
+ final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+ final String exclusiveManagerName =
+ BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
+ FAKE_EXCLUSIVE_MANAGER_NAME);
+ cachedDevices.add(mCachedBluetoothDevice);
+
+ when(mBluetoothAdapter.isEnabled()).thenReturn(true);
+ when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
+ when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+ when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mBluetoothDevice.isConnected()).thenReturn(false);
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+ exclusiveManagerName.getBytes());
+
+ doReturn(new PackageInfo()).when(mPackageManager).getPackageInfo(exclusiveManagerName, 0);
+
+ mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+ verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+ verify(mBluetoothDeviceUpdater, never()).addPreference(mCachedBluetoothDevice,
+ BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
+ public void update_exclusivelyManagedDeviceWithoutPackageInstalled_addDevice()
+ throws Exception {
+ final Collection<CachedBluetoothDevice> cachedDevices = new ArrayList<>();
+ final String exclusiveManagerName =
+ BluetoothUtils.getExclusiveManagers().stream().findAny().orElse(
+ FAKE_EXCLUSIVE_MANAGER_NAME);
+ cachedDevices.add(mCachedBluetoothDevice);
+
+ when(mBluetoothAdapter.isEnabled()).thenReturn(true);
+ when(mBluetoothManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
+ when(mDeviceManager.getCachedDevicesCopy()).thenReturn(cachedDevices);
+ when(mBluetoothDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mBluetoothDevice.isConnected()).thenReturn(false);
+ when(mBluetoothDevice.getMetadata(BluetoothDevice.METADATA_EXCLUSIVE_MANAGER)).thenReturn(
+ exclusiveManagerName.getBytes());
+
+ doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager).getPackageInfo(
+ exclusiveManagerName, 0);
+
+ mBluetoothDeviceUpdater.update(mCachedBluetoothDevice);
+
+ verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice,
+ BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceControllerTest.java
index aa10517..4cdd364 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceControllerTest.java
@@ -171,6 +171,7 @@
mShadowBluetoothAdapter.setEnabled(false);
mController.displayPreference(mScreen);
mController.updateVisibility();
+ shadowOf(Looper.getMainLooper()).idle();
assertThat(mPreference.isVisible()).isFalse();
}
@@ -180,6 +181,7 @@
mShadowBluetoothAdapter.setEnabled(false);
mController.displayPreference(mScreen);
mController.updateVisibility();
+ shadowOf(Looper.getMainLooper()).idle();
assertThat(mPreference.isVisible()).isFalse();
}
@@ -188,6 +190,7 @@
when(mBroadcast.isEnabled(any())).thenReturn(false);
mController.displayPreference(mScreen);
mController.updateVisibility();
+ shadowOf(Looper.getMainLooper()).idle();
assertThat(mPreference.isVisible()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java
index 554227e..14ba337 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatterySettingsFeatureProviderImplTest.java
@@ -22,11 +22,17 @@
import androidx.test.core.app.ApplicationProvider;
+import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
+import java.util.ArrayList;
+
@RunWith(RobolectricTestRunner.class)
public class BatterySettingsFeatureProviderImplTest {
private BatterySettingsFeatureProviderImpl mImpl;
@@ -52,4 +58,15 @@
public void isBatteryInfoEnabled_returnFalse() {
assertThat(mImpl.isBatteryInfoEnabled(mContext)).isFalse();
}
+
+ @Test
+ public void addBatteryTipDetector_containsLowBatteryTip() {
+ var tips = new ArrayList<BatteryTip>();
+
+ mImpl.addBatteryTipDetector(
+ mContext, tips, new BatteryInfo(), new BatteryTipPolicy(mContext));
+
+ var expectedResult = tips.stream().anyMatch(tip -> tip instanceof LowBatteryTip);
+ assertThat(expectedResult).isTrue();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java
index eeedccc..c05d9ed 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipPreferenceControllerTest.java
@@ -20,30 +20,29 @@
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.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Bundle;
-import android.text.format.DateUtils;
import androidx.preference.PreferenceScreen;
+import androidx.test.core.app.ApplicationProvider;
import com.android.settings.SettingsActivity;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
-import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.widget.CardPreference;
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.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.List;
@@ -53,8 +52,8 @@
private static final String KEY_PREF = "battery_tip";
private static final String KEY_TIP = "key_battery_tip";
- private static final long AVERAGE_TIME_MS = DateUtils.HOUR_IN_MILLIS;
+ @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock private BatteryTipPreferenceController.BatteryTipListener mBatteryTipListener;
@Mock private PreferenceScreen mPreferenceScreen;
@Mock private BatteryTip mBatteryTip;
@@ -64,21 +63,16 @@
private Context mContext;
private CardPreference mCardPreference;
private BatteryTipPreferenceController mBatteryTipPreferenceController;
- private List<BatteryTip> mOldBatteryTips;
private List<BatteryTip> mNewBatteryTips;
- private FakeFeatureFactory mFeatureFactory;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
- mContext = RuntimeEnvironment.application;
+ mContext = ApplicationProvider.getApplicationContext();
- mCardPreference = spy(new CardPreference(mContext));
+ mCardPreference = new CardPreference(mContext);
when(mPreferenceScreen.getContext()).thenReturn(mContext);
doReturn(mCardPreference).when(mPreferenceScreen).findPreference(KEY_PREF);
- mFeatureFactory = FakeFeatureFactory.setupForTest();
- mOldBatteryTips = new ArrayList<>();
mNewBatteryTips = new ArrayList<>();
mBatteryTipPreferenceController = buildBatteryTipPreferenceController();
@@ -87,32 +81,32 @@
}
@Test
- public void testDisplayPreference_isInvisible() {
+ public void displayPreference_isInvisible() {
mBatteryTipPreferenceController.displayPreference(mPreferenceScreen);
assertThat(mCardPreference.isVisible()).isFalse();
}
@Test
- public void testUpdateBatteryTips_tipsStateInvisible_isInvisible() {
+ public void updateBatteryTips_tipsStateInvisible_isInvisible() {
mBatteryTipPreferenceController.updateBatteryTips(mNewBatteryTips);
assertThat(mCardPreference.isVisible()).isFalse();
}
@Test
- public void testGetCurrentBatteryTip_noTips_isNull() {
+ public void getCurrentBatteryTip_noTips_isNull() {
assertThat(mBatteryTipPreferenceController.getCurrentBatteryTip()).isNull();
}
@Test
- public void testGetCurrentBatteryTip_tipsInvisible_isNull() {
+ public void getCurrentBatteryTip_tipsInvisible_isNull() {
mBatteryTipPreferenceController.updateBatteryTips(mNewBatteryTips);
assertThat(mBatteryTipPreferenceController.getCurrentBatteryTip()).isNull();
}
@Test
- public void testRestoreFromNull_shouldNotCrash() {
+ public void restoreFromNull_shouldNotCrash() {
final Bundle bundle = new Bundle();
// Battery tip list is null at this time
mBatteryTipPreferenceController.saveInstanceState(bundle);
@@ -124,7 +118,7 @@
}
@Test
- public void testHandlePreferenceTreeClick_noDialog_invokeCallback() {
+ public void handlePreferenceTreeClick_noDialog_invokeCallback() {
when(mBatteryTip.getType()).thenReturn(SMART_BATTERY_MANAGER);
List<BatteryTip> batteryTips = new ArrayList<>();
batteryTips.add(mBatteryTip);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java
index 8e3de7c..c5897f2 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/LowBatteryDetectorTest.java
@@ -19,20 +19,25 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
+import static org.robolectric.Shadows.shadowOf;
import android.content.Context;
+import android.os.PowerManager;
+
+import androidx.test.core.app.ApplicationProvider;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
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.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;
import java.util.concurrent.TimeUnit;
@@ -40,73 +45,79 @@
@RunWith(RobolectricTestRunner.class)
public class LowBatteryDetectorTest {
+ @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
+
@Mock private BatteryInfo mBatteryInfo;
- private BatteryTipPolicy mPolicy;
+
+ private BatteryTipPolicy mBatteryTipPolicy;
private LowBatteryDetector mLowBatteryDetector;
private Context mContext;
+ private PowerManager mPowerManager;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
+ mContext = ApplicationProvider.getApplicationContext();
+ mBatteryTipPolicy = spy(new BatteryTipPolicy(mContext));
- mPolicy = spy(new BatteryTipPolicy(RuntimeEnvironment.application));
- mContext = RuntimeEnvironment.application;
- ReflectionHelpers.setField(mPolicy, "lowBatteryEnabled", true);
+ mPowerManager = mContext.getSystemService(PowerManager.class);
+ shadowOf(mPowerManager).setIsPowerSaveMode(false);
+
+ ReflectionHelpers.setField(mBatteryTipPolicy, "lowBatteryEnabled", true);
mBatteryInfo.discharging = true;
- mLowBatteryDetector =
- new LowBatteryDetector(
- mContext, mPolicy, mBatteryInfo, false /* isPowerSaveMode */);
+ mLowBatteryDetector = new LowBatteryDetector(mContext, mBatteryTipPolicy, mBatteryInfo);
}
@Test
- public void testDetect_disabledByPolicy_tipInvisible() {
- ReflectionHelpers.setField(mPolicy, "lowBatteryEnabled", false);
- mLowBatteryDetector =
- new LowBatteryDetector(mContext, mPolicy, mBatteryInfo, true /* isPowerSaveMode */);
+ public void detect_disabledByPolicy_tipInvisible() {
+ ReflectionHelpers.setField(mBatteryTipPolicy, "lowBatteryEnabled", false);
+ shadowOf(mPowerManager).setIsPowerSaveMode(true);
+ mLowBatteryDetector = new LowBatteryDetector(mContext, mBatteryTipPolicy, mBatteryInfo);
assertThat(mLowBatteryDetector.detect().isVisible()).isFalse();
}
@Test
- public void testDetect_enabledByTest_tipNew() {
- ReflectionHelpers.setField(mPolicy, "testLowBatteryTip", true);
+ public void detect_enabledByTest_tipNew() {
+ ReflectionHelpers.setField(mBatteryTipPolicy, "testLowBatteryTip", true);
assertThat(mLowBatteryDetector.detect().getState()).isEqualTo(BatteryTip.StateType.NEW);
}
@Test
- public void testDetect_lowBattery_tipNew() {
+ public void detect_lowBattery_tipNew() {
mBatteryInfo.batteryLevel = 20;
mBatteryInfo.remainingTimeUs = TimeUnit.DAYS.toMillis(1);
+
assertThat(mLowBatteryDetector.detect().getState()).isEqualTo(BatteryTip.StateType.NEW);
}
@Test
- public void testDetect_batterySaverOn_tipInvisible() {
- mLowBatteryDetector =
- new LowBatteryDetector(mContext, mPolicy, mBatteryInfo, true /* isPowerSaveMode */);
+ public void detect_batterySaverOn_tipInvisible() {
+ shadowOf(mPowerManager).setIsPowerSaveMode(true);
+ mLowBatteryDetector = new LowBatteryDetector(mContext, mBatteryTipPolicy, mBatteryInfo);
assertThat(mLowBatteryDetector.detect().getState())
.isEqualTo(BatteryTip.StateType.INVISIBLE);
}
@Test
- public void testDetect_charging_tipInvisible() {
+ public void detect_charging_tipInvisible() {
mBatteryInfo.discharging = false;
assertThat(mLowBatteryDetector.detect().isVisible()).isFalse();
}
@Test
- public void testDetect_lowTimeEstimation_tipInvisible() {
+ public void detect_lowTimeEstimation_tipInvisible() {
mBatteryInfo.batteryLevel = 50;
mBatteryInfo.remainingTimeUs = TimeUnit.MINUTES.toMillis(1);
+
assertThat(mLowBatteryDetector.detect().isVisible()).isFalse();
}
@Test
- public void testDetect_noEarlyWarning_tipInvisible() {
+ public void detect_noEarlyWarning_tipInvisible() {
mBatteryInfo.remainingTimeUs = TimeUnit.DAYS.toMicros(1);
mBatteryInfo.batteryLevel = 100;
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
index 296306d..4efd850 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
@@ -17,8 +17,6 @@
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -27,6 +25,7 @@
import android.util.Log;
import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
@@ -34,12 +33,13 @@
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
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.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowLog;
@RunWith(RobolectricTestRunner.class)
@@ -49,23 +49,22 @@
private FakeFeatureFactory mFeatureFactory;
private BatteryDefenderTip mBatteryDefenderTip;
private MetricsFeatureProvider mMetricsFeatureProvider;
+ private CardPreference mCardPreference;
+ @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock private BatteryTip mBatteryTip;
@Mock private Preference mPreference;
- @Mock private CardPreference mCardPreference;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
-
+ mContext = ApplicationProvider.getApplicationContext();
mFeatureFactory = FakeFeatureFactory.setupForTest();
mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
- mContext = RuntimeEnvironment.application;
mBatteryDefenderTip =
- new BatteryDefenderTip(BatteryTip.StateType.NEW, false /* isPluggedIn */);
+ new BatteryDefenderTip(BatteryTip.StateType.NEW, /* isPluggedIn= */ false);
+ mCardPreference = new CardPreference(mContext);
when(mPreference.getContext()).thenReturn(mContext);
- when(mCardPreference.getContext()).thenReturn(mContext);
}
@Test
@@ -87,7 +86,7 @@
}
@Test
- public void testLog_logMetric() {
+ public void log_logMetric() {
mBatteryDefenderTip.updateState(mBatteryTip);
mBatteryDefenderTip.log(mContext, mMetricsFeatureProvider);
@@ -108,7 +107,7 @@
mBatteryDefenderTip.updatePreference(mCardPreference);
- verify(mCardPreference).setPrimaryButtonText(expectedText);
+ assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo(expectedText);
}
@Test
@@ -117,46 +116,31 @@
mBatteryDefenderTip.updatePreference(mCardPreference);
- verify(mCardPreference).setSecondaryButtonText(expected);
+ assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo(expected);
}
@Test
public void updatePreference_shouldSetPrimaryButtonVisible() {
mBatteryDefenderTip.updatePreference(mCardPreference);
- verify(mCardPreference).setPrimaryButtonVisible(true);
+ assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
}
@Test
public void updatePreference_whenCharging_setPrimaryButtonVisibleToBeTrue() {
mBatteryDefenderTip =
- new BatteryDefenderTip(BatteryTip.StateType.NEW, true /* isPluggedIn */);
+ new BatteryDefenderTip(BatteryTip.StateType.NEW, /* isPluggedIn= */ true);
mBatteryDefenderTip.updatePreference(mCardPreference);
- verify(mCardPreference).setPrimaryButtonVisible(true);
+ assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
}
@Test
public void updatePreference_whenNotCharging_setSecondaryButtonVisibleToBeFalse() {
mBatteryDefenderTip.updatePreference(mCardPreference);
- verify(mCardPreference).setSecondaryButtonVisible(false);
- }
-
- @Test
- public void updatePreference_whenGetChargingStatusFailed_setSecondaryButtonVisibleToBeFalse() {
- fakeGetChargingStatusFailed();
-
- mBatteryDefenderTip.updatePreference(mCardPreference);
-
- verify(mCardPreference).setSecondaryButtonVisible(false);
- }
-
- private void fakeGetChargingStatusFailed() {
- Context mockContext = mock(Context.class);
- when(mockContext.getString(anyInt())).thenReturn("fake_string");
- when(mCardPreference.getContext()).thenReturn(mockContext);
+ assertThat(mCardPreference.getSecondaryButtonVisibility()).isFalse();
}
private String getLastErrorLog() {
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
index 45fdc1f..097f484 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTipTest.java
@@ -20,11 +20,10 @@
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
-import android.view.View;
import androidx.annotation.DrawableRes;
import androidx.preference.Preference;
-import androidx.preference.PreferenceViewHolder;
+import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.widget.CardPreference;
@@ -32,10 +31,12 @@
import com.android.settingslib.testutils.DrawableTestHelper;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.List;
@@ -47,13 +48,15 @@
private static final String SUMMARY = "summary";
@DrawableRes private static final int ICON_ID = R.drawable.ic_fingerprint;
+ @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
+
private Context mContext;
private TestBatteryTip mBatteryTip;
@Before
public void setUp() {
- mContext = RuntimeEnvironment.application;
mBatteryTip = new TestBatteryTip();
+ mContext = ApplicationProvider.getApplicationContext();
}
@Test
@@ -84,19 +87,14 @@
@Test
public void updatePreference_resetLayoutState() {
- mContext.setTheme(R.style.Theme_Settings);
- PreferenceViewHolder holder =
- PreferenceViewHolder.createInstanceForTests(
- View.inflate(
- mContext, R.layout.card_preference_layout, /* parent= */ null));
CardPreference cardPreference = new CardPreference(mContext);
- cardPreference.onBindViewHolder(holder);
- cardPreference.setPrimaryButtonVisible(true);
+ cardPreference.setPrimaryButtonVisibility(true);
+ cardPreference.setSecondaryButtonVisibility(true);
mBatteryTip.updatePreference(cardPreference);
- View view = holder.findViewById(R.id.card_preference_buttons);
- assertThat(view.getVisibility()).isEqualTo(View.GONE);
+ assertThat(cardPreference.getPrimaryButtonVisibility()).isFalse();
+ assertThat(cardPreference.getSecondaryButtonVisibility()).isFalse();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
index c1d039b..7a23332 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/IncompatibleChargerTipTest.java
@@ -25,6 +25,7 @@
import android.util.Log;
import androidx.preference.Preference;
+import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settings.testutils.FakeFeatureFactory;
@@ -32,12 +33,13 @@
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
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.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
import org.robolectric.shadows.ShadowLog;
@RunWith(RobolectricTestRunner.class)
@@ -47,22 +49,21 @@
private FakeFeatureFactory mFeatureFactory;
private IncompatibleChargerTip mIncompatibleChargerTip;
private MetricsFeatureProvider mMetricsFeatureProvider;
+ private CardPreference mCardPreference;
+ @Rule public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock private BatteryTip mBatteryTip;
@Mock private Preference mPreference;
- @Mock private CardPreference mCardPreference;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
-
mFeatureFactory = FakeFeatureFactory.setupForTest();
mMetricsFeatureProvider = mFeatureFactory.metricsFeatureProvider;
- mContext = RuntimeEnvironment.application;
+ mContext = ApplicationProvider.getApplicationContext();
mIncompatibleChargerTip = new IncompatibleChargerTip(BatteryTip.StateType.NEW);
+ mCardPreference = new CardPreference(mContext);
when(mPreference.getContext()).thenReturn(mContext);
- when(mCardPreference.getContext()).thenReturn(mContext);
}
@Test
@@ -107,13 +108,13 @@
mIncompatibleChargerTip.updatePreference(mCardPreference);
- verify(mCardPreference).setPrimaryButtonText(expected);
+ assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo(expected);
}
@Test
public void updatePreference_shouldSetSecondaryButtonVisible() {
mIncompatibleChargerTip.updatePreference(mCardPreference);
- verify(mCardPreference).setPrimaryButtonVisible(true);
+ assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
}
private String getLastErrorLog() {
diff --git a/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java b/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java
deleted file mode 100644
index e26643f..0000000
--- a/tests/robotests/src/com/android/settings/widget/CardPreferenceTest.java
+++ /dev/null
@@ -1,344 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *Visibility_setGoneForPrimaryButton_buttonGroupIsGone
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.widget;
-
-import static android.view.View.GONE;
-import static android.view.View.VISIBLE;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.content.Context;
-import android.view.View;
-import android.widget.Button;
-
-import androidx.preference.PreferenceViewHolder;
-import androidx.test.core.app.ApplicationProvider;
-
-import com.android.settings.R;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-
-@RunWith(RobolectricTestRunner.class)
-public class CardPreferenceTest {
-
- private CardPreference mCardPreference;
- private PreferenceViewHolder mHolder;
-
- @Before
- public void setUp() {
- Context context = ApplicationProvider.getApplicationContext();
- context.setTheme(R.style.Theme_Settings);
- mCardPreference = new CardPreference(context);
-
- mHolder = PreferenceViewHolder.createInstanceForTests(
- View.inflate(context, R.layout.card_preference_layout, /* parent= */ null));
- }
-
- @Test
- public void newACardPreference_layoutResourceShouldBeCardPreferenceLayout() {
- Context context = ApplicationProvider.getApplicationContext();
- context.setTheme(R.style.SettingsPreferenceTheme);
-
- CardPreference cardPreference = new CardPreference(context);
-
- assertThat(cardPreference.getLayoutResource()).isEqualTo(R.layout.card_preference_layout);
- }
-
- @Test
- public void onBindViewHolder_noButtonVisible_buttonsLayoutIsGone() {
- mCardPreference.onBindViewHolder(mHolder);
-
- assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
- }
-
- @Test
- public void onBindViewHolder_setPrimaryButtonVisibility_buttonsLayoutIsVisible() {
- mCardPreference.setPrimaryButtonVisible(true);
-
- mCardPreference.onBindViewHolder(mHolder);
-
- assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(VISIBLE);
- }
-
- @Test
- public void onBindViewHolder_setPrimaryButtonVisibilityToVisible() {
- mCardPreference.setPrimaryButtonVisible(true);
-
- mCardPreference.onBindViewHolder(mHolder);
-
- assertThat(getPrimaryButton().getVisibility()).isEqualTo(VISIBLE);
- }
-
- @Test
- public void onBindViewHolder_setSecondaryButtonVisibility_buttonsLayoutIsVisible() {
- mCardPreference.setSecondaryButtonVisible(true);
-
- mCardPreference.onBindViewHolder(mHolder);
-
- assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(VISIBLE);
- }
-
- @Test
- public void onBindViewHolder_setSecondaryButtonVisibilityToVisible() {
- mCardPreference.setSecondaryButtonVisible(true);
-
- mCardPreference.onBindViewHolder(mHolder);
-
- assertThat(getSecondaryButton().getVisibility()).isEqualTo(VISIBLE);
- }
-
- @Test
- public void onBindViewHolder_setPrimaryButtonTextToExpectedText() {
- String expectedText = "primary-button";
- mCardPreference.setPrimaryButtonText(expectedText);
-
- mCardPreference.onBindViewHolder(mHolder);
-
- assertThat(getPrimaryButton().getText().toString()).isEqualTo(expectedText);
- }
-
- @Test
- public void onBindViewHolder_setSecondaryButtonTextToExpectedText() {
- String expectedText = "secondary-button";
- mCardPreference.setSecondaryButtonText(expectedText);
-
- mCardPreference.onBindViewHolder(mHolder);
-
- assertThat(getSecondaryButton().getText().toString()).isEqualTo(expectedText);
- }
-
- @Test
- public void onBindViewHolder_initialTextForPrimaryButtonShouldBeEmpty() {
- mCardPreference.onBindViewHolder(mHolder);
-
- assertThat(getPrimaryButton().getText().toString()).isEqualTo("");
- }
-
- @Test
- public void onBindViewHolder_initialTextForSecondaryButtonShouldBeEmpty() {
- mCardPreference.onBindViewHolder(mHolder);
-
- assertThat(getSecondaryButton().getText().toString()).isEqualTo("");
- }
-
- @Test
- public void performClickOnPrimaryButton_callClickListener() {
- final boolean[] hasCalled = {false};
- View.OnClickListener clickListener = v -> hasCalled[0] = true;
- mCardPreference.setPrimaryButtonClickListener(clickListener);
-
- mCardPreference.onBindViewHolder(mHolder);
- getPrimaryButton().performClick();
-
- assertThat(hasCalled[0]).isTrue();
- }
-
- @Test
- public void performClickOnSecondaryButton_callClickListener() {
- final boolean[] hasCalled = {false};
- View.OnClickListener clickListener = v -> hasCalled[0] = true;
- mCardPreference.setSecondaryButtonClickListener(clickListener);
-
- mCardPreference.onBindViewHolder(mHolder);
- getSecondaryButton().performClick();
-
- assertThat(hasCalled[0]).isTrue();
- }
-
- @Test
- public void onBindViewHolder_primaryButtonDefaultIsGone() {
- mCardPreference.onBindViewHolder(mHolder);
-
- assertThat(getPrimaryButton().getVisibility()).isEqualTo(GONE);
- }
-
- @Test
- public void onBindViewHolder_secondaryButtonDefaultIsGone() {
- mCardPreference.onBindViewHolder(mHolder);
-
- assertThat(getSecondaryButton().getVisibility()).isEqualTo(GONE);
- }
-
- @Test
- public void setPrimaryButtonVisibility_setTrueAfterBindViewHolder_isVisible() {
- mCardPreference.setPrimaryButtonVisible(false);
- mCardPreference.onBindViewHolder(mHolder);
-
- mCardPreference.setPrimaryButtonVisible(true);
-
- assertThat(getPrimaryButton().getVisibility()).isEqualTo(VISIBLE);
- }
-
- @Test
- public void setPrimaryButtonText_setAfterBindViewHolder_setOnUi() {
- String expectedText = "123456";
- mCardPreference.onBindViewHolder(mHolder);
-
- mCardPreference.setPrimaryButtonText(expectedText);
-
- assertThat(getPrimaryButton().getText().toString()).isEqualTo(expectedText);
- }
-
- @Test
- public void setPrimaryButtonText_setNull_isEmptyText() {
- final String emptyString = "";
- mCardPreference.setPrimaryButtonText("1234");
- mCardPreference.onBindViewHolder(mHolder);
-
- mCardPreference.setPrimaryButtonText(null);
-
- assertThat(getPrimaryButton().getText().toString()).isEqualTo(emptyString);
- }
-
- @Test
- public void setPrimaryButtonClickListener_setAfterOnBindViewHolder() {
- final String[] hasCalled = {""};
- String expectedClickedResult = "was called";
- View.OnClickListener clickListener = v -> hasCalled[0] = expectedClickedResult;
- mCardPreference.onBindViewHolder(mHolder);
-
- mCardPreference.setPrimaryButtonClickListener(clickListener);
- getPrimaryButton().performClick();
-
- assertThat(hasCalled[0]).isEqualTo(expectedClickedResult);
- }
-
- @Test
- public void setPrimaryButtonClickListener_setNull_clearTheOnClickListener() {
- final String[] hasCalled = {"not called"};
- View.OnClickListener clickListener = v -> hasCalled[0] = "called once";
- mCardPreference.setPrimaryButtonClickListener(clickListener);
- mCardPreference.onBindViewHolder(mHolder);
-
- mCardPreference.setPrimaryButtonClickListener(null);
- getPrimaryButton().performClick();
-
- assertThat(hasCalled[0]).isEqualTo("not called");
- }
-
- @Test
- public void setSecondaryButtonVisibility_setTrueAfterBindViewHolder_isVisible() {
- mCardPreference.setSecondaryButtonVisible(false);
- mCardPreference.onBindViewHolder(mHolder);
-
- mCardPreference.setSecondaryButtonVisible(true);
-
- assertThat(getSecondaryButton().getVisibility()).isEqualTo(VISIBLE);
- }
-
- @Test
- public void setSecondaryButtonText_setAfterBindViewHolder_setOnUi() {
- String expectedText = "10101010";
- mCardPreference.onBindViewHolder(mHolder);
-
- mCardPreference.setSecondaryButtonText(expectedText);
-
- assertThat(getSecondaryButton().getText().toString()).isEqualTo(expectedText);
- }
-
- @Test
- public void setSecondaryButtonText_setNull_isEmptyText() {
- String emptyString = "";
- mCardPreference.setSecondaryButtonText("1234");
- mCardPreference.onBindViewHolder(mHolder);
-
- mCardPreference.setSecondaryButtonText(null);
-
- assertThat(getSecondaryButton().getText().toString()).isEqualTo(emptyString);
- }
-
- @Test
- public void setSecondaryButtonClickListener_setAfterOnBindViewHolder() {
- final String[] hasCalled = {""};
- String expectedClickedResult = "2nd was called";
- View.OnClickListener clickListener = v -> hasCalled[0] = expectedClickedResult;
- mCardPreference.onBindViewHolder(mHolder);
-
- mCardPreference.setSecondaryButtonClickListener(clickListener);
- getSecondaryButton().performClick();
-
- assertThat(hasCalled[0]).isEqualTo(expectedClickedResult);
- }
-
- @Test
- public void setSecondaryButtonClickListener_setNull_clearTheOnClickListener() {
- final String[] hasCalled = {"not called"};
- View.OnClickListener clickListener = v -> hasCalled[0] = "called once";
- mCardPreference.setSecondaryButtonClickListener(clickListener);
- mCardPreference.onBindViewHolder(mHolder);
-
- mCardPreference.setSecondaryButtonClickListener(null);
- getSecondaryButton().performClick();
-
- assertThat(hasCalled[0]).isEqualTo("not called");
- }
-
- @Test
- public void setPrimaryButtonVisibility_setGoneForSecondaryButton_buttonGroupIsGone() {
- mCardPreference.setPrimaryButtonVisible(true);
- mCardPreference.setSecondaryButtonVisible(false);
- mCardPreference.onBindViewHolder(mHolder);
- assertWithMessage("PreCondition: buttonsView should be Visible")
- .that(getCardPreferenceButtonsView().getVisibility())
- .isEqualTo(VISIBLE);
-
- mCardPreference.setPrimaryButtonVisible(false);
-
- assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
- }
-
- @Test
- public void setSecondaryButtonVisibility_setGoneForPrimaryButton_buttonGroupIsGone() {
- mCardPreference.setPrimaryButtonVisible(false);
- mCardPreference.setSecondaryButtonVisible(true);
- mCardPreference.onBindViewHolder(mHolder);
- assertWithMessage("PreCondition: buttonsView should be Visible")
- .that(getCardPreferenceButtonsView().getVisibility())
- .isEqualTo(VISIBLE);
-
- mCardPreference.setSecondaryButtonVisible(false);
-
- assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
- }
-
- @Test
- public void resetLayoutState_buttonGroupIsGone() {
- mCardPreference.setPrimaryButtonVisible(true);
- mCardPreference.setSecondaryButtonVisible(true);
- mCardPreference.onBindViewHolder(mHolder);
-
- mCardPreference.resetLayoutState();
-
- assertThat(getCardPreferenceButtonsView().getVisibility()).isEqualTo(GONE);
- }
-
- private View getCardPreferenceButtonsView() {
- return mHolder.findViewById(R.id.card_preference_buttons);
- }
-
- private Button getPrimaryButton() {
- return (Button) mHolder.findViewById(android.R.id.button1);
- }
-
- private Button getSecondaryButton() {
- return (Button) mHolder.findViewById(android.R.id.button2);
- }
-}
diff --git a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
index 2e6189e..4497a0a 100644
--- a/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/calling/WifiCallingSettingsForSubTest.java
@@ -40,7 +40,10 @@
import android.content.Intent;
import android.os.Bundle;
import android.os.PersistableBundle;
+import android.platform.test.flag.junit.SetFlagsRule;
import android.telephony.CarrierConfigManager;
+import android.telephony.NetworkRegistrationInfo;
+import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsMmTelManager;
import android.view.View;
@@ -48,6 +51,7 @@
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
+import com.android.internal.telephony.flags.Flags;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.network.ims.MockWifiCallingQueryImsState;
@@ -57,6 +61,7 @@
import com.android.settings.widget.SettingsMainSwitchPreference;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -70,6 +75,7 @@
@Config(shadows = ShadowFragment.class)
@RunWith(RobolectricTestRunner.class)
public class WifiCallingSettingsForSubTest {
+ @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
private static final int SUB_ID = 2;
private static final String SWITCH_BAR = "wifi_calling_switch_bar";
@@ -158,6 +164,7 @@
mFragment.onAttach(mContext);
mFragment.onCreate(null);
mFragment.onActivityCreated(null);
+ mSetFlagsRule.disableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG);
}
private void setDefaultCarrierConfigValues() {
@@ -241,6 +248,31 @@
}
@Test
+ public void onResume_overrideWfcRoamingModeWhileUsingNTN_shouldDisableWfcRoaming() {
+ mSetFlagsRule.enableFlags(Flags.FLAG_CARRIER_ENABLED_SATELLITE_FLAG);
+ mBundle.putBoolean(
+ CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, false);
+ mBundle.putBoolean(CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, true);
+ mBundle.putBoolean(
+ CarrierConfigManager.KEY_OVERRIDE_WFC_ROAMING_MODE_WHILE_USING_NTN_BOOL, true);
+
+ // Phone connected to non-terrestrial network
+ NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+ .setIsNonTerrestrialNetwork(true)
+ .build();
+ ServiceState ss = new ServiceState();
+ ss.addNetworkRegistrationInfo(nri);
+ doReturn(ss).when(mTelephonyManager).getServiceState();
+
+ // Call onResume to update the WFC roaming preference.
+ mFragment.onResume();
+
+ // Check that WFC roaming preference is visible but disabled
+ verify(mButtonWfcRoamingMode, times(1)).setEnabled(false);
+ verify(mButtonWfcRoamingMode, times(1)).setVisible(true);
+ }
+
+ @Test
public void onResume_useWfcHomeModeConfigTrueAndNotEditable_shouldHideWfcRoaming() {
mBundle.putBoolean(
CarrierConfigManager.KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL, true);
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt
index 74aa861..537764a 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/WifiControlAppListModelTest.kt
@@ -21,7 +21,6 @@
import android.content.Context
import android.content.pm.ApplicationInfo
import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.lifecycle.MutableLiveData
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
@@ -270,7 +269,7 @@
private class FakeAppOpsController(private val fakeMode: Int) : IAppOpsController {
var setAllowedCalledWith: Boolean? = null
- override val mode = MutableLiveData(fakeMode)
+ override val mode = flowOf(fakeMode)
override fun setAllowed(allowed: Boolean) {
setAllowedCalledWith = allowed
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
index cc2c1e1..b61e3a9 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/HibernationSwitchPreferenceTest.kt
@@ -24,8 +24,9 @@
import android.apphibernation.AppHibernationManager
import android.content.Context
import android.content.pm.ApplicationInfo
-import android.content.pm.Flags
+import android.content.pm.Flags as PmFlags
import android.os.Build
+import android.os.SystemProperties
import android.permission.PermissionControllerManager
import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_ELIGIBLE
import android.permission.PermissionControllerManager.HIBERNATION_ELIGIBILITY_EXEMPT_BY_SYSTEM
@@ -48,6 +49,7 @@
import com.android.settings.R
import com.android.settings.Utils.PROPERTY_APP_HIBERNATION_ENABLED
import com.android.settings.Utils.PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS
+import com.android.settings.flags.Flags
import com.android.settings.testutils.TestDeviceConfig
import com.android.settings.testutils.mockAsUser
import com.android.settingslib.spaprivileged.framework.common.appHibernationManager
@@ -161,8 +163,8 @@
}
private fun isArchivingEnabled() =
- Flags.archiving() || "true" == System.getProperty("pm.archiving.enabled")
-
+ PmFlags.archiving() || SystemProperties.getBoolean("pm.archiving.enabled", false)
+ || Flags.appArchiving()
@Test
fun `An app targets Q with ops mode default when hibernation targets pre S - not exempted`() {
mockOpsMode(MODE_DEFAULT)
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/MediaRoutingControlTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/MediaRoutingControlTest.kt
index 2f4740e..990ec5c 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/MediaRoutingControlTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/specialaccess/MediaRoutingControlTest.kt
@@ -24,7 +24,6 @@
import android.content.Context
import android.content.pm.ApplicationInfo
import android.platform.test.flag.junit.SetFlagsRule
-import androidx.lifecycle.MutableLiveData
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.media.flags.Flags
@@ -33,6 +32,7 @@
import com.android.settingslib.spaprivileged.model.app.IAppOpsController
import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -223,16 +223,13 @@
private class FakeAppOpsController(fakeMode: Int) : IAppOpsController {
- override val mode = MutableLiveData(fakeMode)
+ override val mode = MutableStateFlow(fakeMode)
override fun setAllowed(allowed: Boolean) {
- if (allowed)
- mode.postValue(AppOpsManager.MODE_ALLOWED)
- else
- mode.postValue(AppOpsManager.MODE_ERRORED)
+ mode.value = if (allowed) AppOpsManager.MODE_ALLOWED else AppOpsManager.MODE_ERRORED
}
- override fun getMode(): Int = mode.value!!
+ override fun getMode(): Int = mode.value
}
companion object {
diff --git a/tests/spa_unit/src/com/android/settings/widget/CardPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/widget/CardPreferenceTest.kt
new file mode 100644
index 0000000..0483e36
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/widget/CardPreferenceTest.kt
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.widget
+
+import android.content.Context
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.test.assertContentDescriptionEquals
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settings.R
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class CardPreferenceTest {
+
+ @get:Rule val composeTestRule = createComposeRule()
+ private lateinit var context: Context
+
+ @Before
+ fun setUp() {
+ context = ApplicationProvider.getApplicationContext()
+ }
+
+ @Test
+ fun enableDismiss_whenEnable_shouldBeDisplayed() {
+ composeTestRule.setContent { buildCardPreference(enableDismiss = true) }
+
+ composeTestRule.onNodeWithContentDescription("Dismiss").assertIsDisplayed()
+ }
+
+ @Test
+ fun enableDismiss_whenDisable_shouldBeDisplayed() {
+ composeTestRule.setContent { buildCardPreference(enableDismiss = false) }
+
+ composeTestRule.onNodeWithContentDescription("Dismiss").assertIsNotDisplayed()
+ }
+
+ @Test
+ fun primaryButton_whenVisible_shouldBeDisplayed() {
+ val expectedPrimaryButtonText = "You can see me"
+ composeTestRule.setContent {
+ buildCardPreference(
+ primaryButtonText = expectedPrimaryButtonText,
+ primaryButtonVisibility = true,
+ )
+ }
+
+ composeTestRule.onNodeWithText(expectedPrimaryButtonText).assertIsDisplayed()
+ }
+
+ @Test
+ fun primaryButton_whenInvisible_shouldBeDisplayed() {
+ val expectedButtonText = "You cannot see me"
+ composeTestRule.setContent {
+ buildCardPreference(
+ primaryButtonText = expectedButtonText,
+ primaryButtonVisibility = false,
+ )
+ }
+
+ composeTestRule.onNodeWithText(expectedButtonText).assertIsNotDisplayed()
+ }
+
+ @Test
+ fun primaryButtonAction_whenClick_performAction() {
+ val buttonText = "click me"
+ var clicked = false
+ composeTestRule.setContent {
+ buildCardPreference(
+ primaryButtonText = buttonText,
+ primaryButtonVisibility = true,
+ primaryButtonAction = { clicked = true }
+ )
+ }
+
+ composeTestRule.onNodeWithText(buttonText).performClick()
+
+ assertThat(clicked).isTrue()
+ }
+
+ @Test
+ fun primaryButtonContentDescription_whenSet_shouldBeExists() {
+ val expectedText = "this is a content description"
+ val buttonText = "primary-button"
+ composeTestRule.setContent {
+ buildCardPreference(
+ primaryButtonText = buttonText,
+ primaryButtonContentDescription = expectedText,
+ primaryButtonVisibility = true,
+ )
+ }
+
+ composeTestRule.onNodeWithText(buttonText).assertContentDescriptionEquals(expectedText)
+ }
+
+ @Test
+ fun secondaryButton_whenVisible_shouldBeDisplayed() {
+ val expectedSecondaryButtonText = "You can see me"
+ composeTestRule.setContent {
+ buildCardPreference(
+ secondaryButtonText = expectedSecondaryButtonText,
+ secondaryButtonVisibility = true,
+ )
+ }
+
+ composeTestRule.onNodeWithText(expectedSecondaryButtonText).assertIsDisplayed()
+ }
+
+ @Test
+ fun secondaryButton_whenInvisible_shouldBeDisplayed() {
+ val expectedButtonText = "You cannot see me"
+ composeTestRule.setContent {
+ buildCardPreference(
+ secondaryButtonText = expectedButtonText,
+ secondaryButtonVisibility = false,
+ )
+ }
+
+ composeTestRule.onNodeWithText(expectedButtonText).assertIsNotDisplayed()
+ }
+
+ @Test
+ fun secondaryButtonAction_whenClick_performAction() {
+ val buttonText = "click me2"
+ var clicked = false
+ composeTestRule.setContent {
+ buildCardPreference(
+ secondaryButtonText = buttonText,
+ secondaryButtonVisibility = true,
+ secondaryButtonAction = { clicked = true }
+ )
+ }
+
+ composeTestRule.onNodeWithText(buttonText).performClick()
+
+ assertThat(clicked).isTrue()
+ }
+
+ @Test
+ fun secondaryButtonContentDescription_whenSet_shouldBeExists() {
+ val expectedText = "found bug yay"
+ val buttonText = "secondary-button"
+ composeTestRule.setContent {
+ buildCardPreference(
+ secondaryButtonText = buttonText,
+ secondaryButtonContentDescription = expectedText,
+ secondaryButtonVisibility = true,
+ )
+ }
+
+ composeTestRule.onNodeWithText(buttonText).assertContentDescriptionEquals(expectedText)
+ }
+
+ @Test
+ fun resetLayoutState_shouldRemoveThePrimaryButton() {
+ val buttonText = "9527"
+ val cardPreference =
+ CardPreference(context)
+ .apply {
+ primaryButtonText = buttonText
+ primaryButtonVisibility = true
+ }
+ .also { it.buildContent() }
+
+ cardPreference.resetLayoutState()
+ composeTestRule.setContent { cardPreference.Content() }
+
+ composeTestRule.onNodeWithText(buttonText).assertDoesNotExist()
+ }
+
+ @Test
+ fun resetLayoutState_shouldRemoveTheSecondaryButton() {
+ val buttonText = "4567"
+ val cardPreference =
+ CardPreference(context)
+ .apply {
+ secondaryButtonText = buttonText
+ secondaryButtonVisibility = true
+ }
+ .also { it.buildContent() }
+
+ cardPreference.resetLayoutState()
+ composeTestRule.setContent { cardPreference.Content() }
+
+ composeTestRule.onNodeWithText(buttonText).assertDoesNotExist()
+ }
+
+ @Composable
+ private fun buildCardPreference(
+ iconResId: Int? = R.drawable.ic_battery_status_protected_24dp,
+ primaryButtonText: String = "primary text",
+ primaryButtonContentDescription: String? = "primary description",
+ primaryButtonAction: () -> Unit = {},
+ primaryButtonVisibility: Boolean = false,
+ secondaryButtonText: String = "secondary button",
+ secondaryButtonContentDescription: String? = null,
+ secondaryButtonAction: () -> Unit = {},
+ secondaryButtonVisibility: Boolean = false,
+ enableDismiss: Boolean = true,
+ ) =
+ CardPreference(context)
+ .apply {
+ this.iconResId = iconResId
+ this.primaryButtonText = primaryButtonText
+ this.primaryButtonContentDescription = primaryButtonContentDescription
+ this.primaryButtonAction = primaryButtonAction
+ this.primaryButtonVisibility = primaryButtonVisibility
+ this.secondaryButtonText = secondaryButtonText
+ this.secondaryButtonContentDescription = secondaryButtonContentDescription
+ this.secondaryButtonAction = secondaryButtonAction
+ this.secondaryButtonVisibility = secondaryButtonVisibility
+ this.enableDismiss(enableDismiss)
+ }
+ .also { it.buildContent() }
+ .Content()
+}
diff --git a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
index acf590b..b5aeac7 100644
--- a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java
@@ -17,6 +17,7 @@
package com.android.settings.applications.credentials;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
@@ -55,6 +56,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
@RunWith(AndroidJUnit4.class)
@@ -121,17 +123,34 @@
createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
- controller.setVisibility(true);
- assertThat(controller.getVisibility()).isTrue();
+ controller.setSimulateHiddenForTests(Optional.of(false));
+ assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
+ public void getAvailabilityStatus_isHidden_returnsConditionallyUnavailable() {
+ CredentialManagerPreferenceController controller =
+ createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
+ controller.setSimulateConnectedForTests(true);
+ assertThat(controller.isConnected()).isTrue();
+ controller.setSimulateHiddenForTests(Optional.of(true));
+ assertThat(controller.isHiddenDueToNoProviderSet()).isTrue();
+ assertThat(controller.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
public void displayPreference_withServices_preferencesAdded() {
CredentialManagerPreferenceController controller =
createControllerWithServices(Lists.newArrayList(createCredentialProviderInfo()));
+ controller.setSimulateConnectedForTests(true);
+ controller.setSimulateHiddenForTests(Optional.of(false));
+
+ assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+ assertThat(controller.isConnected()).isTrue();
+ assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+
controller.displayPreference(mScreen);
- assertThat(controller.isConnected()).isFalse();
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(1);
Preference pref = mCredentialsPreferenceCategory.getPreference(0);
@@ -150,8 +169,8 @@
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
- controller.setVisibility(true);
- assertThat(controller.getVisibility()).isTrue();
+ controller.setSimulateHiddenForTests(Optional.of(false));
+ assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
// Test the data is correct.
@@ -194,8 +213,8 @@
createCredentialProviderInfo("com.android.provider6", "ClassA")));
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
- controller.setVisibility(true);
- assertThat(controller.getVisibility()).isTrue();
+ controller.setSimulateHiddenForTests(Optional.of(false));
+ assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
// Ensure that we stay under 5 providers.
@@ -263,8 +282,8 @@
createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2));
controller.setSimulateConnectedForTests(true);
assertThat(controller.isConnected()).isTrue();
- controller.setVisibility(true);
- assertThat(controller.getVisibility()).isTrue();
+ controller.setSimulateHiddenForTests(Optional.of(false));
+ assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
// Test the data is correct.
@@ -316,9 +335,14 @@
CredentialManagerPreferenceController controller =
createControllerWithServices(
Lists.newArrayList(serviceA1, serviceB1, serviceC1, serviceC2, serviceC3));
- controller.displayPreference(mScreen);
+ controller.setSimulateConnectedForTests(true);
+ controller.setSimulateHiddenForTests(Optional.of(false));
- assertThat(controller.isConnected()).isFalse();
+ assertThat(controller.isHiddenDueToNoProviderSet()).isFalse();
+ assertThat(controller.isConnected()).isTrue();
+ assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+
+ controller.displayPreference(mScreen);
assertThat(mCredentialsPreferenceCategory.getPreferenceCount()).isEqualTo(3);
Map<String, CredentialManagerPreferenceController.CombiPreference> prefs =
diff --git a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
index f6356bc..71d419e 100644
--- a/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/BiometricsSafetySourceTest.java
@@ -114,7 +114,7 @@
@Test
public void setSafetySourceData_whenSafetyCenterIsEnabled_withoutBiometrics_setsNullData() {
- when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
+ when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
when(mFaceManager.isHardwareDetected()).thenReturn(false);
diff --git a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
index 3538727..e528c4e 100644
--- a/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
+++ b/tests/unit/src/com/android/settings/safetycenter/LockScreenSafetySourceTest.java
@@ -413,6 +413,8 @@
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
when(mScreenLockPreferenceDetailsUtils.isPasswordQualityManaged(anyInt(), any()))
.thenReturn(false);
+ when(mScreenLockPreferenceDetailsUtils.isLockPatternSecure()).thenReturn(true);
+ when(mScreenLockPreferenceDetailsUtils.shouldShowGearMenu()).thenReturn(true);
LockScreenSafetySource.setSafetySourceData(
mApplicationContext, mScreenLockPreferenceDetailsUtils, EVENT_SOURCE_STATE_CHANGED);
diff --git a/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java
index 9851a1a..31f7878 100644
--- a/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java
+++ b/tests/unit/src/com/android/settings/security/SecurityAdvancedSettingsTest.java
@@ -107,7 +107,7 @@
@Test
public void whenSafetyCenterIsEnabled_pageIndexExcluded() throws Exception {
- when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(false);
+ when(mSafetyCenterManagerWrapper.isEnabled(any())).thenReturn(true);
BaseSearchIndexProvider indexProvider = SecurityAdvancedSettings.SEARCH_INDEX_DATA_PROVIDER;
List<String> allXmlKeys = TestUtils.getAllXmlKeys(mContext, indexProvider);