Merge "Don't show quick settings tooltip if the user is in the Setup Wizard, since the user can't access the Quick Settings Panel." into main
diff --git a/res/layout/content_protection_preference_fragment.xml b/res/layout/content_protection_preference_fragment.xml
index 4c7352e..8bf6582 100644
--- a/res/layout/content_protection_preference_fragment.xml
+++ b/res/layout/content_protection_preference_fragment.xml
@@ -17,6 +17,7 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="content_protection_preference_subpage"
android:title="@string/content_protection_preference_title">
<com.android.settingslib.widget.TopIntroPreference
diff --git a/res/layout/vpn_dialog.xml b/res/layout/vpn_dialog.xml
index 892a176..062772e 100644
--- a/res/layout/vpn_dialog.xml
+++ b/res/layout/vpn_dialog.xml
@@ -66,25 +66,6 @@
<EditText style="@style/vpn_value"
android:id="@+id/server"/>
- <CheckBox style="@style/vpn_value"
- android:id="@+id/mppe"
- android:text="@string/vpn_mppe"
- android:visibility="gone"/>
-
- <LinearLayout android:id="@+id/l2tp"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone">
- <TextView style="@style/vpn_label"
- android:text="@string/vpn_l2tp_secret"
- android:labelFor="@+id/l2tp_secret"/>
- <EditText style="@style/vpn_value"
- android:id="@+id/l2tp_secret"
- android:password="true"
- android:hint="@string/vpn_not_used"/>
- </LinearLayout>
-
<LinearLayout android:id="@+id/options_ipsec_identity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -154,31 +135,6 @@
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone">
- <LinearLayout android:id="@+id/network_options"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
- <TextView style="@style/vpn_label"
- android:text="@string/vpn_search_domains"
- android:labelFor="@+id/search_domains"/>
- <EditText style="@style/vpn_value"
- android:id="@+id/search_domains"
- android:hint="@string/vpn_not_used"/>
-
- <TextView style="@style/vpn_label"
- android:text="@string/vpn_dns_servers"
- android:labelFor="@+id/dns_servers"/>
- <EditText style="@style/vpn_value"
- android:id="@+id/dns_servers"
- android:hint="@string/vpn_not_used"/>
-
- <TextView style="@style/vpn_label"
- android:text="@string/vpn_routes"
- android:labelFor="@+id/routes"/>
- <EditText style="@style/vpn_value"
- android:id="@+id/routes"
- android:hint="@string/vpn_not_used"/>
- </LinearLayout>
<TextView android:id="@+id/vpn_proxy_settings_title"
style="@style/vpn_label"
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 7283be2..f84afec 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -872,15 +872,9 @@
<item>1</item>
</string-array>
- <!-- Match this with the constants in VpnProfile. --> <skip />
+ <!-- Match this with the array VPN_TYPES in ConfigDialog. --> <skip />
<!-- Short names for each VPN type, not really translatable. [CHAR LIMIT=20] -->
<string-array name="vpn_types" translatable="false">
- <item>PPTP</item>
- <item>L2TP/IPSec PSK</item>
- <item>L2TP/IPSec RSA</item>
- <item>IPSec Xauth PSK</item>
- <item>IPSec Xauth RSA</item>
- <item>IPSec Hybrid RSA</item>
<item>IKEv2/IPSec MSCHAPv2</item>
<item>IKEv2/IPSec PSK</item>
<item>IKEv2/IPSec RSA</item>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7406295..cffaaa8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -6440,10 +6440,6 @@
<string name="vpn_type">Type</string>
<!-- Input label for the server address of a VPN profile. [CHAR LIMIT=40] -->
<string name="vpn_server">Server address</string>
- <!-- Checkbox label to enable PPP encryption for a VPN profile. [CHAR LIMIT=40] -->
- <string name="vpn_mppe">PPP encryption (MPPE)</string>
- <!-- Input label for the L2TP secret of a VPN profile. [CHAR LIMIT=40] -->
- <string name="vpn_l2tp_secret">L2TP secret</string>
<!-- Input label for the IPSec identifier of a VPN profile. [CHAR LIMIT=40] -->
<string name="vpn_ipsec_identifier">IPSec identifier</string>
<!-- Input label for the IPSec pre-shared key of a VPN profile. [CHAR LIMIT=40] -->
@@ -6456,12 +6452,6 @@
<string name="vpn_ipsec_server_cert">IPSec server certificate</string>
<!-- Checkbox label to show advanced options of a VPN profile. [CHAR LIMIT=40] -->
<string name="vpn_show_options">Show advanced options</string>
- <!-- Input label for the DNS search domains of a VPN profile. [CHAR LIMIT=40] -->
- <string name="vpn_search_domains">DNS search domains</string>
- <!-- Input label for the DNS servers of a VPN profile. [CHAR LIMIT=40] -->
- <string name="vpn_dns_servers">DNS servers (e.g. 8.8.8.8)</string>
- <!-- Input label for the forwarding routes of a VPN profile. [CHAR LIMIT=40] -->
- <string name="vpn_routes">Forwarding routes (e.g. 10.0.0.0/8)</string>
<!-- Input label for the username of a VPN profile. [CHAR LIMIT=40] -->
<string name="vpn_username">Username</string>
<!-- Input label for the password of a VPN profile. [CHAR LIMIT=40] -->
@@ -6475,22 +6465,6 @@
<!-- Option to use the server certificate received from the VPN server. [CHAR LIMIT=40] -->
<string name="vpn_no_server_cert">(received from server)</string>
<!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled:
- the selected VPN type doesn't support always-on. [CHAR LIMIT=120] -->
- <string name="vpn_always_on_invalid_reason_type">This VPN type can\'t stay connected at all
- times</string>
- <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled:
- the server address is not in numeric form (e.g. 8.8.8.8). [CHAR LIMIT=120] -->
- <string name="vpn_always_on_invalid_reason_server">Always-on VPN only supports numeric server
- addresses</string>
- <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled:
- no DNS is found. [CHAR LIMIT=120] -->
- <string name="vpn_always_on_invalid_reason_no_dns">A DNS server must be specified for always-on
- VPN</string>
- <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled:
- DNS server addresses are not in numeric form (e.g. 8.8.8.8). [CHAR LIMIT=120] -->
- <string name="vpn_always_on_invalid_reason_dns">DNS server addresses must be numeric for
- always-on VPN</string>
- <!-- Error message displayed below the always-on VPN checkbox when the checkbox is disabled:
generic error. [CHAR LIMIT=120] -->
<string name="vpn_always_on_invalid_reason_other">The information entered doesn\'t support
always-on VPN</string>
diff --git a/src/com/android/settings/MainClear.java b/src/com/android/settings/MainClear.java
index 0aba5ca..7b96d42 100644
--- a/src/com/android/settings/MainClear.java
+++ b/src/com/android/settings/MainClear.java
@@ -26,11 +26,13 @@
import android.accounts.AuthenticatorDescription;
import android.app.ActionBar;
import android.app.Activity;
+import android.app.AlertDialog;
import android.app.admin.DevicePolicyManager;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -43,6 +45,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.image.DynamicSystemManager;
import android.provider.Settings;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
@@ -266,6 +269,19 @@
return;
}
+ final DynamicSystemManager dsuManager = (DynamicSystemManager)
+ getActivity().getSystemService(Context.DYNAMIC_SYSTEM_SERVICE);
+ if (dsuManager.isInUse()) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setTitle(R.string.dsu_is_running);
+ builder.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {}
+ });
+ AlertDialog dsuAlertdialog = builder.create();
+ dsuAlertdialog.show();
+ return;
+ }
+
if (runKeyguardConfirmation(KEYGUARD_REQUEST)) {
return;
}
diff --git a/src/com/android/settings/applications/AppStorageSettings.java b/src/com/android/settings/applications/AppStorageSettings.java
index 807f043..e45657f 100644
--- a/src/com/android/settings/applications/AppStorageSettings.java
+++ b/src/com/android/settings/applications/AppStorageSettings.java
@@ -53,6 +53,7 @@
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.deviceinfo.StorageWizardMoveConfirm;
+import com.android.settings.fuelgauge.datasaver.DynamicDenylistManager;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState.Callbacks;
@@ -359,6 +360,8 @@
mButtonsPref.setButton1Enabled(false);
// Invoke uninstall or clear user data based on sysPackage
String packageName = mAppEntry.info.packageName;
+ DynamicDenylistManager.getInstance(getContext())
+ .resetDenylistIfNeeded(packageName, /* force= */ false);
Log.i(TAG, "Clearing user data for package : " + packageName);
if (mClearDataObserver == null) {
mClearDataObserver = new ClearUserDataObserver();
diff --git a/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java b/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java
index 6da3e52..b2b7512 100644
--- a/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java
+++ b/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java
@@ -39,6 +39,7 @@
import com.android.settings.R;
import com.android.settings.fuelgauge.BatteryOptimizeUtils;
+import com.android.settings.fuelgauge.datasaver.DynamicDenylistManager;
import java.util.Arrays;
import java.util.List;
@@ -155,6 +156,8 @@
}
mAom.resetAllModes();
BatteryOptimizeUtils.resetAppOptimizationMode(mContext, mIPm, mAom);
+ DynamicDenylistManager.getInstance(mContext)
+ .resetDenylistIfNeeded(/* packageName= */ null, /* force= */ true);
final int[] restrictedUids = mNpm.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND);
final int currentUserId = ActivityManager.getCurrentUser();
for (int uid : restrictedUids) {
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBasePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBasePreferenceController.java
new file mode 100644
index 0000000..9ebe26d
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBasePreferenceController.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.connecteddevice.audiosharing;
+
+import android.content.Context;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.bluetooth.Utils;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.flags.Flags;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+public abstract class AudioSharingBasePreferenceController extends BasePreferenceController {
+ private final LocalBluetoothManager mBtManager;
+ protected final LocalBluetoothLeBroadcast mBroadcast;
+ protected Preference mPreference;
+
+ public AudioSharingBasePreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ mBtManager = Utils.getLocalBtManager(context);
+ mBroadcast =
+ mBtManager == null
+ ? null
+ : mBtManager.getProfileManager().getLeAudioBroadcastProfile();
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return mBtManager != null && Flags.enableLeAudioSharing()
+ ? AVAILABLE
+ : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ updateVisibility(isBroadcasting());
+ }
+
+ /**
+ * Update the visibility of the preference.
+ *
+ * @param isVisible the latest visibility state for the preference.
+ */
+ public void updateVisibility(boolean isVisible) {
+ mPreference.setVisible(isVisible);
+ }
+
+ private boolean isBroadcasting() {
+ return mBroadcast != null && mBroadcast.isEnabled(null);
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java
index b3b7a2c..40207be 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDashboardFragment.java
@@ -25,11 +25,14 @@
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.widget.SettingsMainSwitchBar;
-public class AudioSharingDashboardFragment extends DashboardFragment {
+public class AudioSharingDashboardFragment extends DashboardFragment
+ implements AudioSharingSwitchBarController.OnSwitchBarChangedListener {
private static final String TAG = "AudioSharingDashboardFrag";
SettingsMainSwitchBar mMainSwitchBar;
private AudioSharingSwitchBarController mSwitchBarController;
+ private CallsAndAlarmsPreferenceController mCallsAndAlarmsPreferenceController;
+ private AudioSharingNamePreferenceController mAudioSharingNamePreferenceController;
public AudioSharingDashboardFragment() {
super();
@@ -63,7 +66,9 @@
@Override
public void onAttach(Context context) {
super.onAttach(context);
- use(CallsAndAlarmsPreferenceController.class).init(this);
+ mCallsAndAlarmsPreferenceController = use(CallsAndAlarmsPreferenceController.class);
+ mCallsAndAlarmsPreferenceController.init(this);
+ mAudioSharingNamePreferenceController = use(AudioSharingNamePreferenceController.class);
}
@Override
@@ -74,9 +79,19 @@
final SettingsActivity activity = (SettingsActivity) getActivity();
mMainSwitchBar = activity.getSwitchBar();
mMainSwitchBar.setTitle(getText(R.string.audio_sharing_switch_title));
- mSwitchBarController = new AudioSharingSwitchBarController(activity, mMainSwitchBar);
+ mSwitchBarController = new AudioSharingSwitchBarController(activity, mMainSwitchBar, this);
mSwitchBarController.init(this);
getSettingsLifecycle().addObserver(mSwitchBarController);
mMainSwitchBar.show();
}
+
+ @Override
+ public void onSwitchBarChanged(boolean newState) {
+ updateVisibilityForAttachedPreferences(newState);
+ }
+
+ private void updateVisibilityForAttachedPreferences(boolean isVisible) {
+ mCallsAndAlarmsPreferenceController.updateVisibility(isVisible);
+ mAudioSharingNamePreferenceController.updateVisibility(isVisible);
+ }
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
index b0f8b8f..0d2b53a 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
@@ -17,7 +17,6 @@
package com.android.settings.connecteddevice.audiosharing;
import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcast;
import android.bluetooth.BluetoothLeBroadcastAssistant;
@@ -43,16 +42,12 @@
import com.android.settings.flags.Flags;
import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LeAudioProfile;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.google.common.collect.ImmutableList;
-
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
@@ -378,13 +373,14 @@
// Do nothing for ineligible (non LE audio) remote device when no sharing session.
} else {
Map<Integer, List<CachedBluetoothDevice>> groupedDevices =
- fetchConnectedDevicesByGroupId();
+ AudioSharingUtils.fetchConnectedDevicesByGroupId(mLocalBtManager);
// Handle connected eligible (LE audio) remote device
if (isBroadcasting()) {
// Show audio sharing switch or join dialog according to device count in the sharing
// session.
ArrayList<AudioSharingDeviceItem> deviceItemsInSharingSession =
- buildDeviceItemsInSharingSession(groupedDevices);
+ AudioSharingUtils.buildOrderedDeviceItemsInSharingSession(
+ groupedDevices, mLocalBtManager);
// Show audio sharing switch dialog when the third eligible (LE audio) remote device
// connected during a sharing session.
if (deviceItemsInSharingSession.size() >= 2) {
@@ -432,8 +428,7 @@
if (device.getGroupId() == cachedDevice.getGroupId()) {
continue;
}
- deviceItems.add(
- new AudioSharingDeviceItem(device.getName(), device.getGroupId()));
+ deviceItems.add(AudioSharingUtils.buildAudioSharingDeviceItem(device));
}
// Show audio sharing join dialog when the second eligible (LE audio) remote device
// connect and no sharing session.
@@ -494,52 +489,6 @@
return mBroadcast != null && mBroadcast.isEnabled(null);
}
- private Map<Integer, List<CachedBluetoothDevice>> fetchConnectedDevicesByGroupId() {
- // TODO: filter out devices with le audio disabled.
- List<BluetoothDevice> connectedDevices =
- mAssistant == null ? ImmutableList.of() : mAssistant.getConnectedDevices();
- Map<Integer, List<CachedBluetoothDevice>> groupedDevices = new HashMap<>();
- CachedBluetoothDeviceManager cacheManager = mLocalBtManager.getCachedDeviceManager();
- for (BluetoothDevice device : connectedDevices) {
- CachedBluetoothDevice cachedDevice = cacheManager.findDevice(device);
- if (cachedDevice == null) {
- Log.d(TAG, "Skip device due to not being cached: " + device.getAnonymizedAddress());
- continue;
- }
- int groupId = cachedDevice.getGroupId();
- if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
- Log.d(
- TAG,
- "Skip device due to no valid group id: " + device.getAnonymizedAddress());
- continue;
- }
- if (!groupedDevices.containsKey(groupId)) {
- groupedDevices.put(groupId, new ArrayList<>());
- }
- groupedDevices.get(groupId).add(cachedDevice);
- }
- return groupedDevices;
- }
-
- private ArrayList<AudioSharingDeviceItem> buildDeviceItemsInSharingSession(
- Map<Integer, List<CachedBluetoothDevice>> groupedDevices) {
- ArrayList<AudioSharingDeviceItem> deviceItems = new ArrayList<>();
- for (List<CachedBluetoothDevice> devices : groupedDevices.values()) {
- for (CachedBluetoothDevice device : devices) {
- List<BluetoothLeBroadcastReceiveState> sourceList =
- mAssistant.getAllSources(device.getDevice());
- if (!sourceList.isEmpty()) {
- // Use random device in the group within the sharing session to
- // represent the group.
- deviceItems.add(
- new AudioSharingDeviceItem(device.getName(), device.getGroupId()));
- break;
- }
- }
- }
- return deviceItems;
- }
-
private void addSourceToTargetDevices(List<BluetoothDevice> sinks) {
if (sinks.isEmpty() || mBroadcast == null || mAssistant == null) {
Log.d(TAG, "Skip adding source to target.");
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceController.java
index 18c9bfd..8336691 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingNamePreferenceController.java
@@ -22,13 +22,10 @@
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
-import com.android.settings.core.BasePreferenceController;
-import com.android.settings.flags.Flags;
import com.android.settings.widget.ValidatedEditTextPreference;
-public class AudioSharingNamePreferenceController extends BasePreferenceController
+public class AudioSharingNamePreferenceController extends AudioSharingBasePreferenceController
implements ValidatedEditTextPreference.Validator,
Preference.OnPreferenceChangeListener,
DefaultLifecycleObserver {
@@ -37,8 +34,6 @@
private static final String PREF_KEY = "audio_sharing_stream_name";
- protected Preference mPreference;
-
private AudioSharingNameTextValidator mAudioSharingNameTextValidator;
public AudioSharingNamePreferenceController(Context context) {
@@ -47,11 +42,6 @@
}
@Override
- public int getAvailabilityStatus() {
- return Flags.enableLeAudioSharing() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
- }
-
- @Override
public String getPreferenceKey() {
return PREF_KEY;
}
@@ -63,12 +53,6 @@
}
@Override
- public void displayPreference(PreferenceScreen screen) {
- super.displayPreference(screen);
- mPreference = screen.findPreference(getPreferenceKey());
- }
-
- @Override
public boolean isTextValid(String value) {
return mAudioSharingNameTextValidator.isTextValid(value);
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
index 83367ae..8b82fe9 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
@@ -16,13 +16,11 @@
package com.android.settings.connecteddevice.audiosharing;
-import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcast;
import android.bluetooth.BluetoothLeBroadcastAssistant;
import android.bluetooth.BluetoothLeBroadcastMetadata;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
-import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.util.Log;
import android.widget.CompoundButton;
@@ -37,17 +35,14 @@
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.flags.Flags;
import com.android.settings.widget.SettingsMainSwitchBar;
+import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.utils.ThreadUtils;
-import com.google.common.collect.ImmutableList;
-
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -58,11 +53,17 @@
implements DefaultLifecycleObserver, OnCheckedChangeListener {
private static final String TAG = "AudioSharingSwitchBarCtl";
private static final String PREF_KEY = "audio_sharing_main_switch";
+
+ interface OnSwitchBarChangedListener {
+ void onSwitchBarChanged(boolean newState);
+ }
+
private final SettingsMainSwitchBar mSwitchBar;
private final LocalBluetoothManager mBtManager;
private final LocalBluetoothLeBroadcast mBroadcast;
private final LocalBluetoothLeBroadcastAssistant mAssistant;
private final Executor mExecutor;
+ private final OnSwitchBarChangedListener mListener;
private DashboardFragment mFragment;
private List<BluetoothDevice> mTargetSinks = new ArrayList<>();
@@ -196,9 +197,11 @@
BluetoothLeBroadcastReceiveState state) {}
};
- AudioSharingSwitchBarController(Context context, SettingsMainSwitchBar switchBar) {
+ AudioSharingSwitchBarController(
+ Context context, SettingsMainSwitchBar switchBar, OnSwitchBarChangedListener listener) {
super(context, PREF_KEY);
mSwitchBar = switchBar;
+ mListener = listener;
mBtManager = Utils.getLocalBtManager(context);
mBroadcast = mBtManager.getProfileManager().getLeAudioBroadcastProfile();
mAssistant = mBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
@@ -265,18 +268,17 @@
mSwitchBar.setEnabled(true);
return;
}
- Map<Integer, List<CachedBluetoothDevice>> groupedDevices = fetchConnectedDevicesByGroupId();
+ Map<Integer, List<CachedBluetoothDevice>> groupedDevices =
+ AudioSharingUtils.fetchConnectedDevicesByGroupId(mBtManager);
ArrayList<AudioSharingDeviceItem> deviceItems = new ArrayList<>();
Optional<Integer> activeGroupId = Optional.empty();
for (List<CachedBluetoothDevice> devices : groupedDevices.values()) {
// Use random device in the group to represent the group.
CachedBluetoothDevice device = devices.get(0);
- // TODO: add BluetoothUtils.isActiveLeAudioDevice to avoid directly using isActiveDevice
- if (device.isActiveDevice(BluetoothProfile.LE_AUDIO)) {
+ if (BluetoothUtils.isActiveLeAudioDevice(device)) {
activeGroupId = Optional.of(device.getGroupId());
} else {
- AudioSharingDeviceItem item =
- new AudioSharingDeviceItem(device.getName(), device.getGroupId());
+ AudioSharingDeviceItem item = AudioSharingUtils.buildAudioSharingDeviceItem(device);
deviceItems.add(item);
}
}
@@ -326,8 +328,12 @@
private void updateSwitch() {
ThreadUtils.postOnMainThread(
() -> {
- mSwitchBar.setChecked(isBroadcasting());
+ boolean isBroadcasting = isBroadcasting();
+ if (mSwitchBar.isChecked() != isBroadcasting) {
+ mSwitchBar.setChecked(isBroadcasting);
+ }
mSwitchBar.setEnabled(true);
+ mListener.onSwitchBarChanged(isBroadcasting);
});
}
@@ -335,31 +341,6 @@
return mBroadcast != null && mBroadcast.isEnabled(null);
}
- private Map<Integer, List<CachedBluetoothDevice>> fetchConnectedDevicesByGroupId() {
- // TODO: filter out devices with le audio disabled.
- List<BluetoothDevice> connectedDevices =
- mAssistant == null ? ImmutableList.of() : mAssistant.getConnectedDevices();
- Map<Integer, List<CachedBluetoothDevice>> groupedDevices = new HashMap<>();
- CachedBluetoothDeviceManager cacheManager = mBtManager.getCachedDeviceManager();
- for (BluetoothDevice device : connectedDevices) {
- CachedBluetoothDevice cachedDevice = cacheManager.findDevice(device);
- if (cachedDevice == null) {
- Log.d(TAG, "Skip device due to not being cached: " + device.getAnonymizedAddress());
- continue;
- }
- int groupId = cachedDevice.getGroupId();
- if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
- Log.d(TAG, "Skip device due to no valid group id");
- continue;
- }
- if (!groupedDevices.containsKey(groupId)) {
- groupedDevices.put(groupId, new ArrayList<>());
- }
- groupedDevices.get(groupId).add(cachedDevice);
- }
- return groupedDevices;
- }
-
private void addSourceToTargetDevices(List<BluetoothDevice> sinks) {
if (sinks.isEmpty() || mBroadcast == null || mAssistant == null) {
Log.d(TAG, "Skip adding source to target.");
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
new file mode 100644
index 0000000..4ece70e
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.connecteddevice.audiosharing;
+
+import android.bluetooth.BluetoothCsipSetCoordinator;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
+import android.util.Log;
+
+import com.android.settingslib.bluetooth.BluetoothUtils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class AudioSharingUtils {
+ private static final String TAG = "AudioSharingUtils";
+
+ /**
+ * Fetch {@link CachedBluetoothDevice}s connected to the broadcast assistant. The devices are
+ * grouped by CSIP group id.
+ *
+ * @param localBtManager The BT manager to provide BT functions.
+ * @return A map of connected devices grouped by CSIP group id.
+ */
+ public static Map<Integer, List<CachedBluetoothDevice>> fetchConnectedDevicesByGroupId(
+ LocalBluetoothManager localBtManager) {
+ Map<Integer, List<CachedBluetoothDevice>> groupedDevices = new HashMap<>();
+ LocalBluetoothLeBroadcastAssistant assistant =
+ localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
+ if (assistant == null) return groupedDevices;
+ // TODO: filter out devices with le audio disabled.
+ List<BluetoothDevice> connectedDevices = assistant.getConnectedDevices();
+ CachedBluetoothDeviceManager cacheManager = localBtManager.getCachedDeviceManager();
+ for (BluetoothDevice device : connectedDevices) {
+ CachedBluetoothDevice cachedDevice = cacheManager.findDevice(device);
+ if (cachedDevice == null) {
+ Log.d(TAG, "Skip device due to not being cached: " + device.getAnonymizedAddress());
+ continue;
+ }
+ int groupId = cachedDevice.getGroupId();
+ if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ Log.d(
+ TAG,
+ "Skip device due to no valid group id: " + device.getAnonymizedAddress());
+ continue;
+ }
+ if (!groupedDevices.containsKey(groupId)) {
+ groupedDevices.put(groupId, new ArrayList<>());
+ }
+ groupedDevices.get(groupId).add(cachedDevice);
+ }
+ return groupedDevices;
+ }
+
+ /**
+ * Fetch a list of {@link AudioSharingDeviceItem}s in the audio sharing session.
+ *
+ * @param groupedConnectedDevices devices connected to broadcast assistant grouped by CSIP group
+ * id.
+ * @param localBtManager The BT manager to provide BT functions.
+ * @return A list of connected devices in the audio sharing session.
+ */
+ public static ArrayList<AudioSharingDeviceItem> buildOrderedDeviceItemsInSharingSession(
+ Map<Integer, List<CachedBluetoothDevice>> groupedConnectedDevices,
+ LocalBluetoothManager localBtManager) {
+ ArrayList<AudioSharingDeviceItem> deviceItems = new ArrayList<>();
+ LocalBluetoothLeBroadcastAssistant assistant =
+ localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
+ if (assistant == null) return deviceItems;
+ CachedBluetoothDevice activeDevice = null;
+ List<CachedBluetoothDevice> inactiveDevices = new ArrayList<>();
+ for (List<CachedBluetoothDevice> devices : groupedConnectedDevices.values()) {
+ for (CachedBluetoothDevice device : devices) {
+ List<BluetoothLeBroadcastReceiveState> sourceList =
+ assistant.getAllSources(device.getDevice());
+ if (!sourceList.isEmpty()) {
+ // Use random device in the group within the sharing session to
+ // represent the group.
+ if (BluetoothUtils.isActiveLeAudioDevice(device)) {
+ activeDevice = device;
+ } else {
+ inactiveDevices.add(device);
+ }
+ break;
+ }
+ }
+ }
+ if (activeDevice != null) {
+ deviceItems.add(buildAudioSharingDeviceItem(activeDevice));
+ }
+ inactiveDevices.stream()
+ .sorted(CachedBluetoothDevice::compareTo)
+ .forEach(
+ device -> {
+ deviceItems.add(buildAudioSharingDeviceItem(device));
+ });
+ return deviceItems;
+ }
+
+ /** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */
+ public static AudioSharingDeviceItem buildAudioSharingDeviceItem(
+ CachedBluetoothDevice cachedDevice) {
+ return new AudioSharingDeviceItem(cachedDevice.getName(), cachedDevice.getGroupId());
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java
index 480b257..44e75ec 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java
@@ -19,21 +19,16 @@
import android.content.Context;
import android.util.Log;
-import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
-import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.DashboardFragment;
-import com.android.settings.flags.Flags;
/** PreferenceController to control the dialog to choose the active device for calls and alarms */
-public class CallsAndAlarmsPreferenceController extends BasePreferenceController {
+public class CallsAndAlarmsPreferenceController extends AudioSharingBasePreferenceController {
private static final String TAG = "CallsAndAlarmsPreferenceController";
private static final String PREF_KEY = "calls_and_alarms";
-
- private Preference mPreference;
private DashboardFragment mFragment;
public CallsAndAlarmsPreferenceController(Context context) {
@@ -41,11 +36,6 @@
}
@Override
- public int getAvailabilityStatus() {
- return Flags.enableLeAudioSharing() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
- }
-
- @Override
public String getPreferenceKey() {
return PREF_KEY;
}
@@ -53,7 +43,6 @@
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- mPreference = screen.findPreference(getPreferenceKey());
mPreference.setOnPreferenceClickListener(
preference -> {
if (mFragment != null) {
diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java
index 38f09f4..fb28d68 100644
--- a/src/com/android/settings/datausage/AppDataUsage.java
+++ b/src/com/android/settings/datausage/AppDataUsage.java
@@ -44,6 +44,7 @@
import com.android.settings.datausage.lib.AppDataUsageDetailsRepository;
import com.android.settings.datausage.lib.NetworkTemplates;
import com.android.settings.datausage.lib.NetworkUsageDetailsData;
+import com.android.settings.fuelgauge.datasaver.DynamicDenylistManager;
import com.android.settings.network.SubscriptionUtil;
import com.android.settings.widget.EntityHeaderController;
import com.android.settingslib.AppItem;
@@ -325,7 +326,8 @@
private boolean getAppRestrictBackground() {
final int uid = mAppItem.key;
final int uidPolicy = services.mPolicyManager.getUidPolicy(uid);
- return (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
+ return (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0
+ && DynamicDenylistManager.getInstance(mContext).isInManualDenylist(uid);
}
private boolean getUnrestrictData() {
diff --git a/src/com/android/settings/datausage/DataSaverBackend.java b/src/com/android/settings/datausage/DataSaverBackend.java
index b4b6b8c..6e99453 100644
--- a/src/com/android/settings/datausage/DataSaverBackend.java
+++ b/src/com/android/settings/datausage/DataSaverBackend.java
@@ -23,6 +23,7 @@
import android.net.NetworkPolicyManager;
import android.util.SparseIntArray;
+import com.android.settings.fuelgauge.datasaver.DynamicDenylistManager;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.utils.ThreadUtils;
@@ -39,6 +40,7 @@
private final MetricsFeatureProvider mMetricsFeatureProvider;
private final NetworkPolicyManager mPolicyManager;
+ private final DynamicDenylistManager mDynamicDenylistManager;
private final ArrayList<Listener> mListeners = new ArrayList<>();
private SparseIntArray mUidPolicies = new SparseIntArray();
private boolean mAllowlistInitialized;
@@ -50,6 +52,7 @@
mContext = context.getApplicationContext();
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
mPolicyManager = NetworkPolicyManager.from(mContext);
+ mDynamicDenylistManager = DynamicDenylistManager.getInstance(mContext);
}
public void addListener(Listener listener) {
@@ -83,7 +86,7 @@
public void setIsAllowlisted(int uid, String packageName, boolean allowlisted) {
final int policy = allowlisted ? POLICY_ALLOW_METERED_BACKGROUND : POLICY_NONE;
- mPolicyManager.setUidPolicy(uid, policy);
+ mDynamicDenylistManager.setUidPolicyLocked(uid, policy);
mUidPolicies.put(uid, policy);
if (allowlisted) {
mMetricsFeatureProvider.action(
@@ -113,7 +116,7 @@
public void setIsDenylisted(int uid, String packageName, boolean denylisted) {
final int policy = denylisted ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE;
- mPolicyManager.setUidPolicy(uid, policy);
+ mDynamicDenylistManager.setUidPolicyLocked(uid, policy);
mUidPolicies.put(uid, policy);
if (denylisted) {
mMetricsFeatureProvider.action(
@@ -123,7 +126,8 @@
public boolean isDenylisted(int uid) {
loadDenylist();
- return mUidPolicies.get(uid, POLICY_NONE) == POLICY_REJECT_METERED_BACKGROUND;
+ return mUidPolicies.get(uid, POLICY_NONE) == POLICY_REJECT_METERED_BACKGROUND
+ && mDynamicDenylistManager.isInManualDenylist(uid);
}
private void loadDenylist() {
diff --git a/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java b/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
index 482858f..e75ab1a 100644
--- a/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
+++ b/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverController.java
@@ -52,9 +52,6 @@
private boolean mShouldToggleSwitchBackOnRebootDialogDismiss;
@VisibleForTesting
- static final String PROPERTY_RO_GFX_ANGLE_SUPPORTED = "ro.gfx.angle.supported";
-
- @VisibleForTesting
static final String PROPERTY_PERSISTENT_GRAPHICS_EGL = "persist.graphics.egl";
@VisibleForTesting
@@ -97,11 +94,6 @@
return mSystemProperties.getBoolean(PROPERTY_DEBUG_ANGLE_DEVELOPER_OPTION, false);
}
- private boolean isAngleSupported() {
- return TextUtils.equals(
- mSystemProperties.get(PROPERTY_RO_GFX_ANGLE_SUPPORTED, ""), "true");
- }
-
@VisibleForTesting
GraphicsDriverEnableAngleAsSystemDriverController(
Context context, DevelopmentSettingsDashboardFragment fragment, Injector injector) {
@@ -145,10 +137,6 @@
/** Return the default value of "persist.graphics.egl" */
public boolean isDefaultValue() {
- if (!isAngleSupported()) {
- return true;
- }
-
final String currentGlesDriver =
mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
// default value of "persist.graphics.egl" is ""
@@ -158,17 +146,11 @@
@Override
public void updateState(Preference preference) {
super.updateState(preference);
- if (isAngleSupported()) {
- // set switch on if "persist.graphics.egl" is "angle" and angle is built in /vendor
- // set switch off otherwise.
- final String currentGlesDriver =
- mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
- final boolean isAngle = TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver);
- ((TwoStatePreference) mPreference).setChecked(isAngle);
- } else {
- mPreference.setEnabled(false);
- ((TwoStatePreference) mPreference).setChecked(false);
- }
+ // set switch on if "persist.graphics.egl" is "angle".
+ final String currentGlesDriver =
+ mSystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
+ final boolean isAngle = TextUtils.equals(ANGLE_DRIVER_SUFFIX, currentGlesDriver);
+ ((TwoStatePreference) mPreference).setChecked(isAngle);
// Disable the developer option toggle UI if ANGLE is disabled, this means next time the
// debug property needs to be set to true again to enable ANGLE. If ANGLE is enabled, don't
@@ -182,12 +164,10 @@
protected void onDeveloperOptionsSwitchDisabled() {
// 1) disable the switch
super.onDeveloperOptionsSwitchDisabled();
- if (isAngleSupported()) {
- // 2) set the persist.graphics.egl empty string
- GraphicsEnvironment.getInstance().toggleAngleAsSystemDriver(false);
- // 3) reset the switch
- ((TwoStatePreference) mPreference).setChecked(false);
- }
+ // 2) set the persist.graphics.egl empty string
+ GraphicsEnvironment.getInstance().toggleAngleAsSystemDriver(false);
+ // 3) reset the switch
+ ((TwoStatePreference) mPreference).setChecked(false);
}
void toggleSwitchBack() {
diff --git a/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java b/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java
index 5d9d047..dd49c8b 100644
--- a/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java
+++ b/src/com/android/settings/fuelgauge/BatterySettingsMigrateChecker.java
@@ -26,6 +26,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.settings.fuelgauge.batterysaver.BatterySaverScheduleRadioButtonsController;
+import com.android.settings.fuelgauge.datasaver.DynamicDenylistManager;
import com.android.settingslib.fuelgauge.BatterySaverUtils;
import java.util.List;
@@ -50,6 +51,8 @@
context = context.getApplicationContext();
verifySaverConfiguration(context);
verifyBatteryOptimizeModes(context);
+ // Initialize and sync settings into SharedPreferences for migration.
+ DynamicDenylistManager.getInstance(context);
}
/** Avoid users set important apps into the unexpected battery optimize modes */
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
index a8be398..bad1b76 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryDiffEntry.java
@@ -27,10 +27,12 @@
import android.util.Log;
import android.util.Pair;
+import androidx.annotation.GuardedBy;
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batteryusage.BatteryEntry.NameAndIcon;
import com.android.settingslib.utils.StringUtil;
import java.util.Comparator;
@@ -40,16 +42,23 @@
/** A container class to carry battery data in a specific time slot. */
public class BatteryDiffEntry {
private static final String TAG = "BatteryDiffEntry";
+ private static final Object sResourceCacheLock = new Object();
+ private static final Object sPackageNameAndUidCacheLock = new Object();
+ private static final Object sValidForRestrictionLock = new Object();
static Locale sCurrentLocale = null;
+
// Caches app label and icon to improve loading performance.
- static final Map<String, BatteryEntry.NameAndIcon> sResourceCache = new ArrayMap<>();
+ @GuardedBy("sResourceCacheLock")
+ static final Map<String, NameAndIcon> sResourceCache = new ArrayMap<>();
// Caches package name and uid to improve loading performance.
+ @GuardedBy("sPackageNameAndUidCacheLock")
static final Map<String, Integer> sPackageNameAndUidCache = new ArrayMap<>();
// Whether a specific item is valid to launch restriction page?
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+ @GuardedBy("sValidForRestrictionLock")
static final Map<String, Boolean> sValidForRestriction = new ArrayMap<>();
/** A comparator for {@link BatteryDiffEntry} based on the sorting key. */
@@ -304,12 +313,16 @@
}
private int getPackageUid(String packageName) {
- if (sPackageNameAndUidCache.containsKey(packageName)) {
- return sPackageNameAndUidCache.get(packageName);
+ synchronized (sPackageNameAndUidCacheLock) {
+ if (sPackageNameAndUidCache.containsKey(packageName)) {
+ return sPackageNameAndUidCache.get(packageName);
+ }
}
int uid = BatteryUtils.getInstance(mContext).getPackageUid(packageName);
- sPackageNameAndUidCache.put(packageName, uid);
+ synchronized (sPackageNameAndUidCacheLock) {
+ sPackageNameAndUidCache.put(packageName, uid);
+ }
return uid;
}
@@ -318,13 +331,16 @@
return;
}
// Checks whether we have cached data or not first before fetching.
- final BatteryEntry.NameAndIcon nameAndIcon = getCache();
+ final NameAndIcon nameAndIcon = getCache();
if (nameAndIcon != null) {
mAppLabel = nameAndIcon.mName;
mAppIcon = nameAndIcon.mIcon;
mAppIconId = nameAndIcon.mIconId;
}
- final Boolean validForRestriction = sValidForRestriction.get(getKey());
+ Boolean validForRestriction = null;
+ synchronized (sValidForRestrictionLock) {
+ validForRestriction = sValidForRestriction.get(getKey());
+ }
if (validForRestriction != null) {
mValidForRestriction = validForRestriction;
}
@@ -336,33 +352,34 @@
// Configures whether we can launch restriction page or not.
updateRestrictionFlagState();
- sValidForRestriction.put(getKey(), Boolean.valueOf(mValidForRestriction));
+ synchronized (sValidForRestrictionLock) {
+ sValidForRestriction.put(getKey(), Boolean.valueOf(mValidForRestriction));
+ }
if (getKey() != null && SPECIAL_ENTRY_MAP.containsKey(getKey())) {
Pair<Integer, Integer> pair = SPECIAL_ENTRY_MAP.get(getKey());
mAppLabel = mContext.getString(pair.first);
mAppIconId = pair.second;
mAppIcon = mContext.getDrawable(mAppIconId);
- sResourceCache.put(
- getKey(), new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, mAppIconId));
+ putResourceCache(getKey(), new NameAndIcon(mAppLabel, mAppIcon, mAppIconId));
return;
}
// Loads application icon and label based on consumer type.
switch (mConsumerType) {
case ConvertUtils.CONSUMER_TYPE_USER_BATTERY:
- final BatteryEntry.NameAndIcon nameAndIconForUser =
+ final NameAndIcon nameAndIconForUser =
BatteryEntry.getNameAndIconFromUserId(mContext, (int) mUserId);
if (nameAndIconForUser != null) {
mAppIcon = nameAndIconForUser.mIcon;
mAppLabel = nameAndIconForUser.mName;
- sResourceCache.put(
+ putResourceCache(
getKey(),
- new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, /* iconId= */ 0));
+ new NameAndIcon(mAppLabel, mAppIcon, /* iconId= */ 0));
}
break;
case ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY:
- final BatteryEntry.NameAndIcon nameAndIconForSystem =
+ final NameAndIcon nameAndIconForSystem =
BatteryEntry.getNameAndIconFromPowerComponent(mContext, mComponentId);
if (nameAndIconForSystem != null) {
mAppLabel = nameAndIconForSystem.mName;
@@ -370,9 +387,8 @@
mAppIconId = nameAndIconForSystem.mIconId;
mAppIcon = mContext.getDrawable(nameAndIconForSystem.mIconId);
}
- sResourceCache.put(
- getKey(),
- new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, mAppIconId));
+ putResourceCache(
+ getKey(), new NameAndIcon(mAppLabel, mAppIcon, mAppIconId));
}
break;
case ConvertUtils.CONSUMER_TYPE_UID_BATTERY:
@@ -384,9 +400,9 @@
// Adds badge icon into app icon for work profile.
mAppIcon = getBadgeIconForUser(mAppIcon);
if (mAppLabel != null || mAppIcon != null) {
- sResourceCache.put(
+ putResourceCache(
getKey(),
- new BatteryEntry.NameAndIcon(mAppLabel, mAppIcon, /* iconId= */ 0));
+ new NameAndIcon(mAppLabel, mAppIcon, /* iconId= */ 0));
}
break;
}
@@ -429,7 +445,7 @@
}
}
- private BatteryEntry.NameAndIcon getCache() {
+ private NameAndIcon getCache() {
final Locale locale = Locale.getDefault();
if (sCurrentLocale != locale) {
Log.d(
@@ -440,7 +456,9 @@
sCurrentLocale = locale;
clearCache();
}
- return sResourceCache.get(getKey());
+ synchronized (sResourceCacheLock) {
+ return sResourceCache.get(getKey());
+ }
}
private void loadNameAndIconForUid() {
@@ -469,13 +487,13 @@
final String[] packages = packageManager.getPackagesForUid(uid);
// Loads special defined application label and icon if available.
if (packages == null || packages.length == 0) {
- final BatteryEntry.NameAndIcon nameAndIcon =
+ final NameAndIcon nameAndIcon =
BatteryEntry.getNameAndIconFromUid(mContext, mAppLabel, uid);
mAppLabel = nameAndIcon.mName;
mAppIcon = nameAndIcon.mIcon;
}
- final BatteryEntry.NameAndIcon nameAndIcon =
+ final NameAndIcon nameAndIcon =
BatteryEntry.loadNameAndIcon(
mContext, uid, /* batteryEntry= */ null, packageName, mAppLabel, mAppIcon);
// Clears BatteryEntry internal cache since we will have another one.
@@ -544,9 +562,21 @@
/** Clears all cache data. */
public static void clearCache() {
- sResourceCache.clear();
- sValidForRestriction.clear();
- sPackageNameAndUidCache.clear();
+ synchronized (sResourceCacheLock) {
+ sResourceCache.clear();
+ }
+ synchronized (sValidForRestrictionLock) {
+ sValidForRestriction.clear();
+ }
+ synchronized (sPackageNameAndUidCacheLock) {
+ sPackageNameAndUidCache.clear();
+ }
+ }
+
+ private static void putResourceCache(String key, NameAndIcon nameAndIcon) {
+ synchronized (sResourceCacheLock) {
+ sResourceCache.put(key, nameAndIcon);
+ }
}
private Drawable getBadgeIconForUser(Drawable icon) {
diff --git a/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManager.java b/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManager.java
index be72e56..7eae7eb 100644
--- a/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManager.java
+++ b/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManager.java
@@ -16,12 +16,24 @@
package com.android.settings.fuelgauge.datasaver;
+import static android.net.NetworkPolicyManager.POLICY_NONE;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
+
+import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
+import static com.android.settings.fuelgauge.BatteryUtils.UID_ZERO;
+
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
import android.net.NetworkPolicyManager;
+import android.util.ArraySet;
+import android.util.Log;
import androidx.annotation.VisibleForTesting;
+import java.util.List;
+import java.util.Set;
+
/** A class to dynamically manage per apps {@link NetworkPolicyManager} POLICY_ flags. */
public final class DynamicDenylistManager {
@@ -29,47 +41,157 @@
private static final String PREF_KEY_MANUAL_DENY = "manual_denylist_preference";
private static final String PREF_KEY_DYNAMIC_DENY = "dynamic_denylist_preference";
+ private static DynamicDenylistManager sInstance;
+
private final Context mContext;
private final NetworkPolicyManager mNetworkPolicyManager;
+ private final Object mLock = new Object();
- private static DynamicDenylistManager sInstance;
+ @VisibleForTesting
+ static final String PREF_KEY_MANUAL_DENYLIST_SYNCED = "manual_denylist_synced";
/** @return a DynamicDenylistManager object */
public static DynamicDenylistManager getInstance(Context context) {
synchronized (DynamicDenylistManager.class) {
if (sInstance == null) {
- sInstance = new DynamicDenylistManager(context);
+ sInstance = new DynamicDenylistManager(
+ context, NetworkPolicyManager.from(context));
}
return sInstance;
}
}
- DynamicDenylistManager(Context context) {
+ @VisibleForTesting
+ DynamicDenylistManager(Context context, NetworkPolicyManager networkPolicyManager) {
mContext = context.getApplicationContext();
- mNetworkPolicyManager = NetworkPolicyManager.from(mContext);
+ mNetworkPolicyManager = networkPolicyManager;
+ syncPolicyIfNeeded();
}
- /** Update the target uid policy in {@link #getManualDenylistPref()}. */
- public void updateManualDenylist(String uid, int policy) {
- if (policy != NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND) {
- getManualDenylistPref().edit().remove(uid).apply();
- } else {
- getManualDenylistPref().edit().putInt(uid, policy).apply();
+ /** Sync the policy from {@link NetworkPolicyManager} if needed. */
+ private void syncPolicyIfNeeded() {
+ if (getManualDenylistPref().contains(PREF_KEY_MANUAL_DENYLIST_SYNCED)) {
+ Log.i(TAG, "syncPolicyIfNeeded() ignore synced manual denylist");
+ return;
+ }
+
+ final SharedPreferences.Editor editor = getManualDenylistPref().edit();
+ final int[] existedUids = mNetworkPolicyManager
+ .getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND);
+ if (existedUids != null && existedUids.length != 0) {
+ for (int uid : existedUids) {
+ editor.putInt(String.valueOf(uid), POLICY_REJECT_METERED_BACKGROUND);
+ }
+ }
+ editor.putInt(PREF_KEY_MANUAL_DENYLIST_SYNCED, POLICY_NONE).apply();
+ }
+
+ /** Set policy flags for specific UID. */
+ public void setUidPolicyLocked(int uid, int policy) {
+ synchronized (mLock) {
+ mNetworkPolicyManager.setUidPolicy(uid, policy);
+ }
+ updateDenylistPref(uid, policy);
+ }
+
+ /** Suggest a list of package to set as POLICY_REJECT. */
+ public void setDenylist(List<String> packageNameList) {
+ final Set<Integer> denylistTargetUids = new ArraySet<>(packageNameList.size());
+ for (String packageName : packageNameList) {
+ try {
+ final int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
+ if (uid == UID_ZERO) {
+ continue;
+ }
+ denylistTargetUids.add(uid);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Unknown package name: " + packageName, e);
+ }
+ }
+
+ final Set<Integer> manualDenylistUids = getDenylistAllUids(getManualDenylistPref());
+ denylistTargetUids.removeAll(manualDenylistUids);
+
+ final Set<Integer> lastDynamicDenylistUids = getDenylistAllUids(getDynamicDenylistPref());
+ if (lastDynamicDenylistUids.equals(denylistTargetUids)) {
+ Log.i(TAG, "setDenylist() ignore the same denylist with size: "
+ + lastDynamicDenylistUids.size());
+ return;
+ }
+
+ // Store target denied uids into DynamicDenylistPref.
+ final SharedPreferences.Editor editor = getDynamicDenylistPref().edit();
+ editor.clear();
+ denylistTargetUids.forEach(
+ uid -> editor.putInt(String.valueOf(uid), POLICY_REJECT_METERED_BACKGROUND));
+ editor.apply();
+
+ // Set new added UIDs into REJECT policy.
+ synchronized (mLock) {
+ for (int uid : denylistTargetUids) {
+ if (!lastDynamicDenylistUids.contains(uid)) {
+ mNetworkPolicyManager.setUidPolicy(uid, POLICY_REJECT_METERED_BACKGROUND);
+ }
+ }
+ }
+ // Unset removed UIDs back to NONE policy.
+ synchronized (mLock) {
+ for (int uid : lastDynamicDenylistUids) {
+ if (!denylistTargetUids.contains(uid)) {
+ mNetworkPolicyManager.setUidPolicy(uid, POLICY_NONE);
+ }
+ }
}
}
/** Return true if the target uid is in {@link #getManualDenylistPref()}. */
- public boolean isInManualDenylist(String uid) {
- return getManualDenylistPref().contains(uid);
+ public boolean isInManualDenylist(int uid) {
+ return getManualDenylistPref().contains(String.valueOf(uid));
}
- /** Clear all data in {@link #getManualDenylistPref()} */
- public void clearManualDenylistPref() {
+ /** Reset the UIDs in the denylist if needed. */
+ public void resetDenylistIfNeeded(String packageName, boolean force) {
+ if (!force && !SETTINGS_PACKAGE_NAME.equals(packageName)) {
+ return;
+ }
+ synchronized (mLock) {
+ for (int uid : mNetworkPolicyManager
+ .getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) {
+ if (!getDenylistAllUids(getManualDenylistPref()).contains(uid)) {
+ mNetworkPolicyManager.setUidPolicy(uid, POLICY_NONE);
+ }
+ }
+ }
+ clearSharedPreferences();
+ }
+
+ private Set<Integer> getDenylistAllUids(SharedPreferences sharedPreferences) {
+ final ArraySet<Integer> uids = new ArraySet<>();
+ for (String key : sharedPreferences.getAll().keySet()) {
+ if (PREF_KEY_MANUAL_DENYLIST_SYNCED.equals(key)) {
+ continue;
+ }
+ try {
+ uids.add(Integer.parseInt(key));
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "getDenylistAllUids() unexpected format for " + key);
+ }
+ }
+ return uids;
+ }
+
+ void updateDenylistPref(int uid, int policy) {
+ final String uidString = String.valueOf(uid);
+ if (policy != POLICY_REJECT_METERED_BACKGROUND) {
+ getManualDenylistPref().edit().remove(uidString).apply();
+ } else {
+ getManualDenylistPref().edit().putInt(uidString, policy).apply();
+ }
+ getDynamicDenylistPref().edit().remove(uidString).apply();
+ }
+
+ void clearSharedPreferences() {
getManualDenylistPref().edit().clear().apply();
- }
-
- /** Clear all data in {@link #getDynamicDenylistPref()} */
- public void clearDynamicDenylistPref() {
getDynamicDenylistPref().edit().clear().apply();
}
diff --git a/src/com/android/settings/localepicker/LocaleLinearLayoutManager.java b/src/com/android/settings/localepicker/LocaleLinearLayoutManager.java
index 8795bf9..59a5fb0 100644
--- a/src/com/android/settings/localepicker/LocaleLinearLayoutManager.java
+++ b/src/com/android/settings/localepicker/LocaleLinearLayoutManager.java
@@ -43,6 +43,7 @@
public class LocaleLinearLayoutManager extends LinearLayoutManager {
private final LocaleDragAndDropAdapter mAdapter;
private final Context mContext;
+ private LocaleListEditor mLocaleListEditor;
private final AccessibilityNodeInfoCompat.AccessibilityActionCompat mActionMoveUp;
private final AccessibilityNodeInfoCompat.AccessibilityActionCompat mActionMoveDown;
@@ -147,8 +148,12 @@
}
if (result) {
- mAdapter.doTheUpdate();
+ mLocaleListEditor.showConfirmDialog(false, mAdapter.getFeedItemList().get(0));
}
return result;
}
+
+ public void setLocaleListEditor(LocaleListEditor localeListEditor) {
+ mLocaleListEditor = localeListEditor;
+ }
}
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index 28f066a..59a39c8 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -472,6 +472,7 @@
private void configureDragAndDrop(LayoutPreference layout) {
final RecyclerView list = layout.findViewById(R.id.dragList);
final LocaleLinearLayoutManager llm = new LocaleLinearLayoutManager(getContext(), mAdapter);
+ llm.setLocaleListEditor(this);
llm.setAutoMeasureEnabled(true);
list.setLayoutManager(llm);
list.setHasFixedSize(true);
@@ -505,7 +506,7 @@
return false;
}
- private void showConfirmDialog(boolean isFirstRemoved, LocaleStore.LocaleInfo localeInfo) {
+ public void showConfirmDialog(boolean isFirstRemoved, LocaleStore.LocaleInfo localeInfo) {
Locale currentSystemLocale = LocalePicker.getLocales().get(0);
if (!localeInfo.getLocale().equals(currentSystemLocale)) {
final LocaleDialogFragment localeDialogFragment =
diff --git a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
index 70d4d7d..a0db4ce 100644
--- a/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
+++ b/src/com/android/settings/password/ConfirmDeviceCredentialActivity.java
@@ -31,6 +31,7 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.UserProperties;
import android.content.res.Configuration;
import android.graphics.Color;
import android.hardware.biometrics.BiometricConstants;
@@ -61,11 +62,6 @@
public class ConfirmDeviceCredentialActivity extends FragmentActivity {
public static final String TAG = ConfirmDeviceCredentialActivity.class.getSimpleName();
- // The normal flow that apps go through
- private static final int CREDENTIAL_NORMAL = 1;
- // Unlocks the managed profile when the primary profile is unlocked
- private static final int CREDENTIAL_MANAGED = 2;
-
private static final String TAG_BIOMETRIC_FRAGMENT = "fragment";
public static class InternalActivity extends ConfirmDeviceCredentialActivity {
@@ -84,7 +80,9 @@
private String mTitle;
private CharSequence mDetails;
private int mUserId;
- private int mCredentialMode;
+ // Used to force the verification path required to unlock profile that shares credentials with
+ // with parent
+ private boolean mForceVerifyPath = false;
private boolean mGoingToBackground;
private boolean mWaitingForBiometricCallback;
@@ -189,7 +187,9 @@
}
final int effectiveUserId = mUserManager.getCredentialOwnerProfile(mUserId);
final boolean isEffectiveUserManagedProfile =
- UserManager.get(this).isManagedProfile(effectiveUserId);
+ mUserManager.isManagedProfile(effectiveUserId);
+ final UserProperties userProperties =
+ mUserManager.getUserProperties(UserHandle.of(mUserId));
// if the client app did not hand in a title and we are about to show the work challenge,
// check whether there is a policy setting the organization name and use that as title
if ((mTitle == null) && isEffectiveUserManagedProfile) {
@@ -278,7 +278,19 @@
.setForceVerifyPath(true)
.show();
} else if (isEffectiveUserManagedProfile && isInternalActivity()) {
- mCredentialMode = CREDENTIAL_MANAGED;
+ // When the mForceVerifyPath is set to true, we launch the real confirm credential
+ // activity with an explicit but fake challenge value (0L). This will result in
+ // ConfirmLockPassword calling verifyTiedProfileChallenge() (if it's a profile with
+ // unified challenge), due to the difference between
+ // ConfirmLockPassword.startVerifyPassword() and
+ // ConfirmLockPassword.startCheckPassword(). Calling verifyTiedProfileChallenge() here
+ // is necessary when this is part of the turning on work profile flow, because it forces
+ // unlocking the work profile even before the profile is running.
+ // TODO: Remove the duplication of checkPassword and verifyPassword in
+ // ConfirmLockPassword,
+ // LockPatternChecker and LockPatternUtils. verifyPassword should be the only API to
+ // use, which optionally accepts a challenge.
+ mForceVerifyPath = true;
if (isBiometricAllowed(effectiveUserId, mUserId)) {
showBiometricPrompt(promptInfo);
launchedBiometric = true;
@@ -286,8 +298,19 @@
showConfirmCredentials();
launchedCDC = true;
}
+ } else if (android.os.Flags.allowPrivateProfile()
+ && userProperties != null
+ && userProperties.isAuthAlwaysRequiredToDisableQuietMode()
+ && isInternalActivity()) {
+ // Force verification path is required to be invoked as we might need to verify the tied
+ // profile challenge if the profile is using the unified challenge mode. This would
+ // result in ConfirmLockPassword.startVerifyPassword/
+ // ConfirmLockPattern.startVerifyPattern being called instead of the
+ // startCheckPassword/startCheckPattern
+ mForceVerifyPath = userProperties.isCredentialShareableWithParent();
+ showConfirmCredentials();
+ launchedCDC = true;
} else {
- mCredentialMode = CREDENTIAL_NORMAL;
if (isBiometricAllowed(effectiveUserId, mUserId)) {
// Don't need to check if biometrics / pin/pattern/pass are enrolled. It will go to
// onAuthenticationError and do the right thing automatically.
@@ -313,11 +336,8 @@
private String getTitleFromCredentialType(@LockPatternUtils.CredentialType int credentialType,
boolean isEffectiveUserManagedProfile) {
- int overrideStringId;
- int defaultStringId;
switch (credentialType) {
case LockPatternUtils.CREDENTIAL_TYPE_PIN:
-
if (isEffectiveUserManagedProfile) {
return mDevicePolicyManager.getResources().getString(
CONFIRM_WORK_PROFILE_PIN_HEADER,
@@ -410,29 +430,15 @@
* Shows ConfirmDeviceCredentials for normal apps.
*/
private void showConfirmCredentials() {
- boolean launched = false;
- ChooseLockSettingsHelper.Builder builder = new ChooseLockSettingsHelper.Builder(this)
+ boolean launched = new ChooseLockSettingsHelper.Builder(this)
.setHeader(mTitle)
.setDescription(mDetails)
.setExternal(true)
.setUserId(mUserId)
- .setTaskOverlay(mTaskOverlay);
- // The only difference between CREDENTIAL_MANAGED and CREDENTIAL_NORMAL is that for
- // CREDENTIAL_MANAGED, we launch the real confirm credential activity with an explicit
- // but fake challenge value (0L). This will result in ConfirmLockPassword calling
- // verifyTiedProfileChallenge() (if it's a profile with unified challenge), due to the
- // difference between ConfirmLockPassword.startVerifyPassword() and
- // ConfirmLockPassword.startCheckPassword(). Calling verifyTiedProfileChallenge() here is
- // necessary when this is part of the turning on work profile flow, because it forces
- // unlocking the work profile even before the profile is running.
- // TODO: Remove the duplication of checkPassword and verifyPassword in ConfirmLockPassword,
- // LockPatternChecker and LockPatternUtils. verifyPassword should be the only API to use,
- // which optionally accepts a challenge.
- if (mCredentialMode == CREDENTIAL_MANAGED) {
- launched = builder.setForceVerifyPath(true).show();
- } else if (mCredentialMode == CREDENTIAL_NORMAL) {
- launched = builder.show();
- }
+ .setTaskOverlay(mTaskOverlay)
+ .setForceVerifyPath(mForceVerifyPath)
+ .show();
+
if (!launched) {
Log.d(TAG, "No pin/pattern/pass set");
setResult(Activity.RESULT_OK);
diff --git a/src/com/android/settings/privatespace/HidePrivateSpaceController.java b/src/com/android/settings/privatespace/HidePrivateSpaceController.java
index b972a3f..8a0f167 100644
--- a/src/com/android/settings/privatespace/HidePrivateSpaceController.java
+++ b/src/com/android/settings/privatespace/HidePrivateSpaceController.java
@@ -16,10 +16,10 @@
package com.android.settings.privatespace;
-import static android.provider.Settings.Secure.HIDE_PRIVATESPACE_ENTRY_POINT;
+import static com.android.settings.privatespace.PrivateSpaceMaintainer.HIDE_PRIVATE_SPACE_ENTRY_POINT_DISABLED_VAL;
+import static com.android.settings.privatespace.PrivateSpaceMaintainer.HIDE_PRIVATE_SPACE_ENTRY_POINT_ENABLED_VAL;
import android.content.Context;
-import android.provider.Settings;
import com.android.settings.core.TogglePreferenceController;
@@ -28,11 +28,11 @@
* in All Apps.
*/
public class HidePrivateSpaceController extends TogglePreferenceController {
- private static final int DISABLED_VALUE = 0;
- private static final int ENABLED_VALUE = 1;
+ private final PrivateSpaceMaintainer mPrivateSpaceMaintainer;
public HidePrivateSpaceController(Context context, String key) {
super(context, key);
+ mPrivateSpaceMaintainer = PrivateSpaceMaintainer.getInstance(context);
}
@Override
@@ -43,14 +43,15 @@
@Override
public boolean isChecked() {
- return Settings.Secure.getInt(mContext.getContentResolver(),
- HIDE_PRIVATESPACE_ENTRY_POINT, DISABLED_VALUE) != DISABLED_VALUE;
+ return mPrivateSpaceMaintainer.getHidePrivateSpaceEntryPointSetting()
+ != HIDE_PRIVATE_SPACE_ENTRY_POINT_DISABLED_VAL;
}
@Override
public boolean setChecked(boolean isChecked) {
- Settings.Secure.putInt(mContext.getContentResolver(), HIDE_PRIVATESPACE_ENTRY_POINT,
- isChecked ? ENABLED_VALUE : DISABLED_VALUE);
+ mPrivateSpaceMaintainer.setHidePrivateSpaceEntryPointSetting(
+ isChecked ? HIDE_PRIVATE_SPACE_ENTRY_POINT_ENABLED_VAL
+ : HIDE_PRIVATE_SPACE_ENTRY_POINT_DISABLED_VAL);
return true;
}
diff --git a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java
index e6094ce..341110b 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceMaintainer.java
@@ -17,6 +17,7 @@
package com.android.settings.privatespace;
import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE;
+import static android.provider.Settings.Secure.HIDE_PRIVATESPACE_ENTRY_POINT;
import android.app.ActivityManager;
import android.app.IActivityManager;
@@ -27,6 +28,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.util.ArraySet;
import android.util.Log;
@@ -40,6 +42,7 @@
/** A class to help with the creation / deletion of Private Space */
public class PrivateSpaceMaintainer {
private static final String TAG = "PrivateSpaceMaintainer";
+
@GuardedBy("this")
private static PrivateSpaceMaintainer sPrivateSpaceMaintainer;
@@ -49,6 +52,10 @@
private UserHandle mUserHandle;
private final KeyguardManager mKeyguardManager;
+ /** This is the default value for the hide private space entry point settings. */
+ public static final int HIDE_PRIVATE_SPACE_ENTRY_POINT_DISABLED_VAL = 0;
+ public static final int HIDE_PRIVATE_SPACE_ENTRY_POINT_ENABLED_VAL = 1;
+
public enum ErrorDeletingPrivateSpace {
DELETE_PS_ERROR_NONE,
DELETE_PS_ERROR_NO_PRIVATE_SPACE,
@@ -91,6 +98,7 @@
}
Log.i(TAG, "Private space created with id: " + mUserHandle.getIdentifier());
+ resetPrivateSpaceSettings();
}
return true;
}
@@ -197,4 +205,21 @@
return doesPrivateSpaceExist()
&& mKeyguardManager.isDeviceSecure(mUserHandle.getIdentifier());
}
+
+ /** Sets the setting to show PS entry point to the provided value. */
+ public void setHidePrivateSpaceEntryPointSetting(int value) {
+ Settings.Secure.putInt(mContext.getContentResolver(), HIDE_PRIVATESPACE_ENTRY_POINT, value);
+ }
+
+ /** @return the setting to show PS entry point. */
+ public int getHidePrivateSpaceEntryPointSetting() {
+ return Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ HIDE_PRIVATESPACE_ENTRY_POINT,
+ HIDE_PRIVATE_SPACE_ENTRY_POINT_DISABLED_VAL);
+ }
+
+ private void resetPrivateSpaceSettings() {
+ setHidePrivateSpaceEntryPointSetting(HIDE_PRIVATE_SPACE_ENTRY_POINT_DISABLED_VAL);
+ }
}
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index 64699ff..29d136f 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -1724,6 +1724,9 @@
public List<SearchIndexableRaw> getRawDataToIndex(Context context,
boolean enabled) {
final List<SearchIndexableRaw> rawData = new ArrayList<>();
+ if (!UserManager.supportsMultipleUsers()) {
+ return rawData;
+ }
SearchIndexableRaw allowMultipleUsersResult = new SearchIndexableRaw(context);
diff --git a/src/com/android/settings/vpn2/ConfigDialog.java b/src/com/android/settings/vpn2/ConfigDialog.java
index 036487d..1c001cb 100644
--- a/src/com/android/settings/vpn2/ConfigDialog.java
+++ b/src/com/android/settings/vpn2/ConfigDialog.java
@@ -16,8 +16,6 @@
package com.android.settings.vpn2;
-import static com.android.internal.net.VpnProfile.isLegacyType;
-
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
@@ -43,9 +41,6 @@
import com.android.settings.R;
import com.android.settings.utils.AndroidKeystoreAliasLoader;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -60,13 +55,18 @@
View.OnClickListener, AdapterView.OnItemSelectedListener,
CompoundButton.OnCheckedChangeListener {
private static final String TAG = "ConfigDialog";
+ // Vpn profile constants to match with R.array.vpn_types.
+ private static final List<Integer> VPN_TYPES = List.of(
+ VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS,
+ VpnProfile.TYPE_IKEV2_IPSEC_PSK,
+ VpnProfile.TYPE_IKEV2_IPSEC_RSA
+ );
+
private final DialogInterface.OnClickListener mListener;
private final VpnProfile mProfile;
private boolean mEditing;
private boolean mExists;
- private List<String> mTotalTypes;
- private List<String> mAllowedTypes;
private View mView;
@@ -75,14 +75,9 @@
private TextView mServer;
private TextView mUsername;
private TextView mPassword;
- private TextView mSearchDomains;
- private TextView mDnsServers;
- private TextView mRoutes;
private Spinner mProxySettings;
private TextView mProxyHost;
private TextView mProxyPort;
- private CheckBox mMppe;
- private TextView mL2tpSecret;
private TextView mIpsecIdentifier;
private TextView mIpsecSecret;
private Spinner mIpsecUserCert;
@@ -116,14 +111,9 @@
mServer = (TextView) mView.findViewById(R.id.server);
mUsername = (TextView) mView.findViewById(R.id.username);
mPassword = (TextView) mView.findViewById(R.id.password);
- mSearchDomains = (TextView) mView.findViewById(R.id.search_domains);
- mDnsServers = (TextView) mView.findViewById(R.id.dns_servers);
- mRoutes = (TextView) mView.findViewById(R.id.routes);
mProxySettings = (Spinner) mView.findViewById(R.id.vpn_proxy_settings);
mProxyHost = (TextView) mView.findViewById(R.id.vpn_proxy_host);
mProxyPort = (TextView) mView.findViewById(R.id.vpn_proxy_port);
- mMppe = (CheckBox) mView.findViewById(R.id.mppe);
- mL2tpSecret = (TextView) mView.findViewById(R.id.l2tp_secret);
mIpsecIdentifier = (TextView) mView.findViewById(R.id.ipsec_identifier);
mIpsecSecret = (TextView) mView.findViewById(R.id.ipsec_secret);
mIpsecUserCert = (Spinner) mView.findViewById(R.id.ipsec_user_cert);
@@ -137,29 +127,17 @@
// Second, copy values from the profile.
mName.setText(mProfile.name);
setTypesByFeature(mType);
- // Not all types will be available to the user. Find the index corresponding to the
- // string of the profile's type.
- if (mAllowedTypes != null && mTotalTypes != null) {
- mType.setSelection(mAllowedTypes.indexOf(mTotalTypes.get(mProfile.type)));
- } else {
- Log.w(TAG, "Allowed or Total vpn types not initialized when setting initial selection");
- }
+ mType.setSelection(convertVpnProfileConstantToTypeIndex(mProfile.type));
mServer.setText(mProfile.server);
if (mProfile.saveLogin) {
mUsername.setText(mProfile.username);
mPassword.setText(mProfile.password);
}
- mSearchDomains.setText(mProfile.searchDomains);
- mDnsServers.setText(mProfile.dnsServers);
- mRoutes.setText(mProfile.routes);
if (mProfile.proxy != null) {
mProxyHost.setText(mProfile.proxy.getHost());
int port = mProfile.proxy.getPort();
mProxyPort.setText(port == 0 ? "" : Integer.toString(port));
}
- mMppe.setChecked(mProfile.mppe);
- mL2tpSecret.setText(mProfile.l2tpSecret);
- mL2tpSecret.setTextAppearance(android.R.style.TextAppearance_DeviceDefault_Medium);
mIpsecIdentifier.setText(mProfile.ipsecIdentifier);
mIpsecSecret.setText(mProfile.ipsecSecret);
final AndroidKeystoreAliasLoader androidKeystoreAliasLoader =
@@ -185,8 +163,6 @@
mServer.addTextChangedListener(this);
mUsername.addTextChangedListener(this);
mPassword.addTextChangedListener(this);
- mDnsServers.addTextChangedListener(this);
- mRoutes.addTextChangedListener(this);
mProxySettings.setOnItemSelectedListener(this);
mProxyHost.addTextChangedListener(this);
mProxyPort.addTextChangedListener(this);
@@ -217,12 +193,6 @@
// Create a button to forget the profile if it has already been saved..
setButton(DialogInterface.BUTTON_NEUTRAL,
context.getString(R.string.vpn_forget), mListener);
-
- // Display warning subtitle if the existing VPN is an insecure type...
- if (VpnProfile.isLegacyType(mProfile.type)) {
- TextView subtitle = mView.findViewById(R.id.dialog_alert_subtitle);
- subtitle.setVisibility(View.VISIBLE);
- }
}
// Create a button to save the profile.
@@ -285,10 +255,7 @@
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (parent == mType) {
- // Because the spinner may not display all available types,
- // convert the selected position into the actual vpn profile type integer.
- final int profileType = convertAllowedIndexToProfileType(position);
- changeType(profileType);
+ changeType(VPN_TYPES.get(position));
} else if (parent == mProxySettings) {
updateProxyFieldsVisibility(position);
}
@@ -330,17 +297,7 @@
} else {
mAlwaysOnVpn.setChecked(false);
mAlwaysOnVpn.setEnabled(false);
- if (!profile.isTypeValidForLockdown()) {
- mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_type);
- } else if (isLegacyType(profile.type) && !profile.isServerAddressNumeric()) {
- mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_server);
- } else if (isLegacyType(profile.type) && !profile.hasDns()) {
- mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_no_dns);
- } else if (isLegacyType(profile.type) && !profile.areDnsAddressesNumeric()) {
- mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_dns);
- } else {
- mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_other);
- }
+ mAlwaysOnInvalidReason.setText(R.string.vpn_always_on_invalid_reason_other);
mAlwaysOnInvalidReason.setVisibility(View.VISIBLE);
}
@@ -370,21 +327,14 @@
}
private boolean isAdvancedOptionsEnabled() {
- return mSearchDomains.getText().length() > 0 || mDnsServers.getText().length() > 0 ||
- mRoutes.getText().length() > 0 || mProxyHost.getText().length() > 0
- || mProxyPort.getText().length() > 0;
+ return mProxyHost.getText().length() > 0 || mProxyPort.getText().length() > 0;
}
private void configureAdvancedOptionsVisibility() {
if (mShowOptions.isChecked() || isAdvancedOptionsEnabled()) {
mView.findViewById(R.id.options).setVisibility(View.VISIBLE);
mShowOptions.setVisibility(View.GONE);
-
- // Configure networking option visibility
// TODO(b/149070123): Add ability for platform VPNs to support DNS & routes
- final int visibility =
- isLegacyType(getSelectedVpnType()) ? View.VISIBLE : View.GONE;
- mView.findViewById(R.id.network_options).setVisibility(visibility);
} else {
mView.findViewById(R.id.options).setVisibility(View.GONE);
mShowOptions.setVisibility(View.VISIBLE);
@@ -393,8 +343,6 @@
private void changeType(int type) {
// First, hide everything.
- mMppe.setVisibility(View.GONE);
- mView.findViewById(R.id.l2tp).setVisibility(View.GONE);
mView.findViewById(R.id.ipsec_psk).setVisibility(View.GONE);
mView.findViewById(R.id.ipsec_user).setVisibility(View.GONE);
mView.findViewById(R.id.ipsec_peer).setVisibility(View.GONE);
@@ -403,34 +351,18 @@
setUsernamePasswordVisibility(type);
// Always enable identity for IKEv2/IPsec profiles.
- if (!isLegacyType(type)) {
- mView.findViewById(R.id.options_ipsec_identity).setVisibility(View.VISIBLE);
- }
+ mView.findViewById(R.id.options_ipsec_identity).setVisibility(View.VISIBLE);
// Then, unhide type-specific fields.
switch (type) {
- case VpnProfile.TYPE_PPTP:
- mMppe.setVisibility(View.VISIBLE);
- break;
-
- case VpnProfile.TYPE_L2TP_IPSEC_PSK:
- mView.findViewById(R.id.l2tp).setVisibility(View.VISIBLE);
- // fall through
- case VpnProfile.TYPE_IKEV2_IPSEC_PSK: // fall through
- case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
+ case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
mView.findViewById(R.id.ipsec_psk).setVisibility(View.VISIBLE);
mView.findViewById(R.id.options_ipsec_identity).setVisibility(View.VISIBLE);
break;
-
- case VpnProfile.TYPE_L2TP_IPSEC_RSA:
- mView.findViewById(R.id.l2tp).setVisibility(View.VISIBLE);
- // fall through
- case VpnProfile.TYPE_IKEV2_IPSEC_RSA: // fall through
- case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
+ case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
mView.findViewById(R.id.ipsec_user).setVisibility(View.VISIBLE);
// fall through
- case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: // fall through
- case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
+ case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
mView.findViewById(R.id.ipsec_peer).setVisibility(View.VISIBLE);
break;
}
@@ -443,7 +375,8 @@
return false;
}
- final int type = getSelectedVpnType();
+ final int position = mType.getSelectedItemPosition();
+ final int type = VPN_TYPES.get(position);
if (!editing && requiresUsernamePassword(type)) {
return mUsername.getText().length() != 0 && mPassword.getText().length() != 0;
}
@@ -451,15 +384,8 @@
return false;
}
- // TODO(b/149070123): Add ability for platform VPNs to support DNS & routes
- if (isLegacyType(mProfile.type)
- && (!validateAddresses(mDnsServers.getText().toString(), false)
- || !validateAddresses(mRoutes.getText().toString(), true))) {
- return false;
- }
-
// All IKEv2 methods require an identifier
- if (!isLegacyType(mProfile.type) && mIpsecIdentifier.getText().length() == 0) {
+ if (mIpsecIdentifier.getText().length() == 0) {
return false;
}
@@ -468,56 +394,23 @@
}
switch (type) {
- case VpnProfile.TYPE_PPTP: // fall through
- case VpnProfile.TYPE_IPSEC_HYBRID_RSA: // fall through
case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
return true;
- case VpnProfile.TYPE_IKEV2_IPSEC_PSK: // fall through
- case VpnProfile.TYPE_L2TP_IPSEC_PSK: // fall through
- case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
+ case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
return mIpsecSecret.getText().length() != 0;
- case VpnProfile.TYPE_IKEV2_IPSEC_RSA: // fall through
- case VpnProfile.TYPE_L2TP_IPSEC_RSA: // fall through
- case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
+ case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
return mIpsecUserCert.getSelectedItemPosition() != 0;
}
return false;
}
- private boolean validateAddresses(String addresses, boolean cidr) {
- try {
- for (String address : addresses.split(" ")) {
- if (address.isEmpty()) {
- continue;
- }
- // Legacy VPN currently only supports IPv4.
- int prefixLength = 32;
- if (cidr) {
- String[] parts = address.split("/", 2);
- address = parts[0];
- prefixLength = Integer.parseInt(parts[1]);
- }
- byte[] bytes = InetAddress.parseNumericAddress(address).getAddress();
- int integer = (bytes[3] & 0xFF) | (bytes[2] & 0xFF) << 8 |
- (bytes[1] & 0xFF) << 16 | (bytes[0] & 0xFF) << 24;
- if (bytes.length != 4 || prefixLength < 0 || prefixLength > 32 ||
- (prefixLength < 32 && (integer << prefixLength) != 0)) {
- return false;
- }
- }
- } catch (Exception e) {
- return false;
- }
- return true;
- }
-
private void setTypesByFeature(Spinner typeSpinner) {
String[] types = getContext().getResources().getStringArray(R.array.vpn_types);
- mTotalTypes = new ArrayList<>(Arrays.asList(types));
- mAllowedTypes = new ArrayList<>(Arrays.asList(types));
-
+ if (types.length != VPN_TYPES.size()) {
+ Log.wtf(TAG, "VPN_TYPES array length does not match string array");
+ }
// Although FEATURE_IPSEC_TUNNELS should always be present in android S and beyond,
// keep this check here just to be safe.
if (!getContext().getPackageManager().hasSystemFeature(
@@ -532,17 +425,6 @@
mProfile.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS;
}
- // Remove all types which are legacy types from the typesList
- if (!VpnProfile.isLegacyType(mProfile.type)) {
- for (int i = mAllowedTypes.size() - 1; i >= 0; i--) {
- // This must be removed from back to front in order to ensure index consistency
- if (VpnProfile.isLegacyType(i)) {
- mAllowedTypes.remove(i);
- }
- }
-
- types = mAllowedTypes.toArray(new String[0]);
- }
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(
getContext(), android.R.layout.simple_spinner_item, types);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
@@ -606,20 +488,14 @@
// First, save common fields.
VpnProfile profile = new VpnProfile(mProfile.key);
profile.name = mName.getText().toString();
- profile.type = getSelectedVpnType();
+ final int position = mType.getSelectedItemPosition();
+ profile.type = VPN_TYPES.get(position);
profile.server = mServer.getText().toString().trim();
profile.username = mUsername.getText().toString();
profile.password = mPassword.getText().toString();
// Save fields based on VPN type.
- if (isLegacyType(profile.type)) {
- // TODO(b/149070123): Add ability for platform VPNs to support DNS & routes
- profile.searchDomains = mSearchDomains.getText().toString().trim();
- profile.dnsServers = mDnsServers.getText().toString().trim();
- profile.routes = mRoutes.getText().toString().trim();
- } else {
- profile.ipsecIdentifier = mIpsecIdentifier.getText().toString();
- }
+ profile.ipsecIdentifier = mIpsecIdentifier.getText().toString();
if (hasProxy()) {
String proxyHost = mProxyHost.getText().toString().trim();
@@ -640,34 +516,17 @@
}
// Then, save type-specific fields.
switch (profile.type) {
- case VpnProfile.TYPE_PPTP:
- profile.mppe = mMppe.isChecked();
- break;
-
- case VpnProfile.TYPE_L2TP_IPSEC_PSK:
- profile.l2tpSecret = mL2tpSecret.getText().toString();
- // fall through
- case VpnProfile.TYPE_IKEV2_IPSEC_PSK: // fall through
- case VpnProfile.TYPE_IPSEC_XAUTH_PSK:
- profile.ipsecIdentifier = mIpsecIdentifier.getText().toString();
+ case VpnProfile.TYPE_IKEV2_IPSEC_PSK:
profile.ipsecSecret = mIpsecSecret.getText().toString();
break;
case VpnProfile.TYPE_IKEV2_IPSEC_RSA:
if (mIpsecUserCert.getSelectedItemPosition() != 0) {
- profile.ipsecSecret = (String) mIpsecUserCert.getSelectedItem();
- }
- // fall through
- case VpnProfile.TYPE_L2TP_IPSEC_RSA:
- profile.l2tpSecret = mL2tpSecret.getText().toString();
- // fall through
- case VpnProfile.TYPE_IPSEC_XAUTH_RSA:
- if (mIpsecUserCert.getSelectedItemPosition() != 0) {
profile.ipsecUserCert = (String) mIpsecUserCert.getSelectedItem();
+ profile.ipsecSecret = profile.ipsecUserCert;
}
// fall through
- case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: // fall through
- case VpnProfile.TYPE_IPSEC_HYBRID_RSA:
+ case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS:
if (mIpsecCaCert.getSelectedItemPosition() != 0) {
profile.ipsecCaCert = (String) mIpsecCaCert.getSelectedItem();
}
@@ -692,19 +551,13 @@
return ProxyUtils.validate(host, port, "") == ProxyUtils.PROXY_VALID;
}
- private int getSelectedVpnType() {
- return convertAllowedIndexToProfileType(mType.getSelectedItemPosition());
- }
-
- private int convertAllowedIndexToProfileType(int allowedSelectedPosition) {
- if (mAllowedTypes != null && mTotalTypes != null) {
- final String typeString = mAllowedTypes.get(allowedSelectedPosition);
- final int profileType = mTotalTypes.indexOf(typeString);
- return profileType;
- } else {
- Log.w(TAG, "Allowed or Total vpn types not initialized when converting protileType");
- return allowedSelectedPosition;
+ private int convertVpnProfileConstantToTypeIndex(int vpnType) {
+ final int typeIndex = VPN_TYPES.indexOf(vpnType);
+ if (typeIndex == -1) {
+ // Existing legacy profile type
+ Log.wtf(TAG, "Invalid existing profile type");
+ return 0;
}
+ return typeIndex;
}
-
}
diff --git a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
index 7b7c7a6..1d841fa 100644
--- a/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
+++ b/tests/robotests/src/com/android/settings/datausage/AppDataUsageTest.java
@@ -239,6 +239,7 @@
ReflectionHelpers.setField(mFragment, "mUnrestrictedData", unrestrictedDataPref);
ReflectionHelpers.setField(mFragment, "mDataSaverBackend", dataSaverBackend);
ReflectionHelpers.setField(mFragment.services, "mPolicyManager", networkPolicyManager);
+ ReflectionHelpers.setField(mFragment, "mContext", RuntimeEnvironment.application);
when(mFragment.getListView()).thenReturn(mock(RecyclerView.class));
ShadowRestrictedLockUtilsInternal.setRestricted(true);
diff --git a/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java b/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java
index 686df7a..e623eb8 100644
--- a/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerTest.java
@@ -19,7 +19,6 @@
import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.ANGLE_DRIVER_SUFFIX;
import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.PROPERTY_DEBUG_ANGLE_DEVELOPER_OPTION;
import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.PROPERTY_PERSISTENT_GRAPHICS_EGL;
-import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.PROPERTY_RO_GFX_ANGLE_SUPPORTED;
import static com.google.common.truth.Truth.assertThat;
@@ -83,7 +82,6 @@
@Test
public void onPreferenceChange_switchOn_shouldEnableAngleAsSystemDriver() {
- ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
// since GraphicsEnvironment is mocked in Robolectric test environment,
// we will override the system property persist.graphics.egl as if it is changed by
// mGraphicsEnvironment.toggleAngleAsSystemDriver(true).
@@ -100,7 +98,6 @@
@Test
public void onPreferenceChange_switchOff_shouldDisableAngleAsSystemDriver() {
- ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
// since GraphicsEnvironment is mocked in Robolectric test environment,
// we will override the system property persist.graphics.egl as if it is changed by
// mGraphicsEnvironment.toggleAngleAsSystemDriver(false).
@@ -116,30 +113,14 @@
}
@Test
- public void updateState_angleNotSupported_preferenceShouldNotBeChecked() {
- ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "");
- mController.updateState(mPreference);
- verify(mPreference).setChecked(false);
- }
-
- @Test
- public void updateState_angleNotSupported_preferenceShouldNotBeEnabled() {
- ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "");
- mController.updateState(mPreference);
- verify(mPreference).setEnabled(false);
- }
-
- @Test
- public void updateState_angleSupported_angleUsed_preferenceShouldBeChecked() {
- ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
+ public void updateState_angleUsed_preferenceShouldBeChecked() {
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, ANGLE_DRIVER_SUFFIX);
mController.updateState(mPreference);
verify(mPreference).setChecked(true);
}
@Test
- public void updateState_angleSupported_angleNotUsed_preferenceShouldNotBeChecked() {
- ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
+ public void updateState_angleNotUsed_preferenceShouldNotBeChecked() {
ShadowSystemProperties.override(PROPERTY_PERSISTENT_GRAPHICS_EGL, "");
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
@@ -147,7 +128,6 @@
@Test
public void onDeveloperOptionSwitchDisabled_shouldDisableAngleAsSystemDriver() {
- ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
mController.onDeveloperOptionsSwitchDisabled();
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
assertThat(systemEGLDriver).isEqualTo("");
@@ -155,14 +135,12 @@
@Test
public void onDeveloperOptionSwitchDisabled_preferenceShouldNotBeChecked() {
- ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
mController.onDeveloperOptionsSwitchDisabled();
verify(mPreference).setChecked(false);
}
@Test
public void onDeveloperOptionsSwitchDisabled_preferenceShouldNotBeEnabled() {
- ShadowSystemProperties.override(PROPERTY_RO_GFX_ANGLE_SUPPORTED, "true");
mController.onDeveloperOptionsSwitchDisabled();
verify(mPreference).setEnabled(false);
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManagerTest.java
index cdf1514..bfa7cfa 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManagerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/datasaver/DynamicDenylistManagerTest.java
@@ -19,138 +19,373 @@
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
+import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
+import static com.android.settings.fuelgauge.datasaver.DynamicDenylistManager.PREF_KEY_MANUAL_DENYLIST_SYNCED;
+
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+import android.net.NetworkPolicyManager;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import java.util.Collections;
+import java.util.List;
+
@RunWith(RobolectricTestRunner.class)
public class DynamicDenylistManagerTest {
- private static final String FAKE_UID_1 = "package_uid_1";
- private static final String FAKE_UID_2 = "package_uid_2";
+ private static final int[] EMPTY_ARRAY = new int[]{};
+ private static final String FAKE_UID_1 = "1001";
+ private static final String FAKE_UID_2 = "1002";
+ private static final int FAKE_UID_1_INT = Integer.parseInt(FAKE_UID_1);
+ private static final int FAKE_UID_2_INT = Integer.parseInt(FAKE_UID_2);
private SharedPreferences mManualDenyListPref;
private SharedPreferences mDynamicDenyListPref;
private DynamicDenylistManager mDynamicDenylistManager;
- private Context mContext;
+
+ @Mock
+ private NetworkPolicyManager mNetworkPolicyManager;
+ @Mock
+ private PackageManager mPackageManager;
@Before
public void setUp() {
- mContext = RuntimeEnvironment.application.getApplicationContext();
- mDynamicDenylistManager = new DynamicDenylistManager(mContext);
- mManualDenyListPref = mDynamicDenylistManager.getManualDenylistPref();
- mDynamicDenyListPref = mDynamicDenylistManager.getDynamicDenylistPref();
+ MockitoAnnotations.initMocks(this);
}
@After
public void tearDown() {
- mDynamicDenylistManager.clearManualDenylistPref();
- mDynamicDenylistManager.clearDynamicDenylistPref();
+ mDynamicDenylistManager.clearSharedPreferences();
}
@Test
- public void getManualDenylistPref_isEmpty() {
- assertThat(mManualDenyListPref.getAll()).isEmpty();
+ public void init_withoutExistedRejectPolicy_createWithExpectedValue() {
+ initDynamicDenylistManager(EMPTY_ARRAY);
+
+ assertThat(mManualDenyListPref.getAll()).hasSize(1);
+ assertTrue(mManualDenyListPref.contains(PREF_KEY_MANUAL_DENYLIST_SYNCED));
}
@Test
- public void getDynamicDenylistPref_isEmpty() {
- assertThat(mDynamicDenyListPref.getAll()).isEmpty();
+ public void init_withExistedRejectPolicy_createWithExpectedValue() {
+ initDynamicDenylistManager(new int[]{FAKE_UID_1_INT, FAKE_UID_2_INT});
+
+ assertThat(mManualDenyListPref.getAll()).hasSize(3);
+ assertTrue(mManualDenyListPref.contains(PREF_KEY_MANUAL_DENYLIST_SYNCED));
+ assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
+ assertTrue(mManualDenyListPref.contains(FAKE_UID_2));
}
@Test
public void getManualDenylistPref_initiated_containsExpectedValue() {
- mManualDenyListPref.edit().putInt(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND).apply();
+ initDynamicDenylistManager(EMPTY_ARRAY);
- assertThat(mManualDenyListPref.getAll().size()).isEqualTo(1);
+ setupPreference(mManualDenyListPref, FAKE_UID_1);
+
assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
}
@Test
public void getDynamicDenylistPref_initiated_containsExpectedValue() {
- mDynamicDenyListPref.edit().putInt(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND).apply();
+ initDynamicDenylistManager(EMPTY_ARRAY);
- assertThat(mDynamicDenyListPref.getAll()).hasSize(1);
+ setupPreference(mDynamicDenyListPref, FAKE_UID_1);
+
assertTrue(mDynamicDenyListPref.contains(FAKE_UID_1));
}
@Test
public void updateManualDenylist_policyReject_addsUid() {
- mDynamicDenylistManager.updateManualDenylist(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND);
+ initDynamicDenylistManager(EMPTY_ARRAY);
- assertThat(mManualDenyListPref.getAll()).hasSize(1);
+ mDynamicDenylistManager.updateDenylistPref(FAKE_UID_1_INT,
+ POLICY_REJECT_METERED_BACKGROUND);
+
assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
}
@Test
public void updateManualDenylist_policyNone_removesUid() {
- mManualDenyListPref.edit().putInt(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND).apply();
+ initDynamicDenylistManager(EMPTY_ARRAY);
+ setupPreference(mManualDenyListPref, FAKE_UID_1);
assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
- mDynamicDenylistManager.updateManualDenylist(FAKE_UID_1, POLICY_NONE);
+ mDynamicDenylistManager.updateDenylistPref(FAKE_UID_1_INT, POLICY_NONE);
- assertThat(mManualDenyListPref.getAll()).isEmpty();
+ assertFalse(mManualDenyListPref.contains(FAKE_UID_1));
}
@Test
public void updateManualDenylist_samePolicy_doNothing() {
- mManualDenyListPref.edit().putInt(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND).apply();
+ initDynamicDenylistManager(EMPTY_ARRAY);
+ setupPreference(mManualDenyListPref, FAKE_UID_1);
assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
+ assertThat(mManualDenyListPref.getAll()).hasSize(2);
- mDynamicDenylistManager.updateManualDenylist(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND);
+ mDynamicDenylistManager.updateDenylistPref(FAKE_UID_1_INT,
+ POLICY_REJECT_METERED_BACKGROUND);
- assertThat(mManualDenyListPref.getAll()).hasSize(1);
+ assertThat(mManualDenyListPref.getAll()).hasSize(2);
}
@Test
- public void isManualDenylist_returnsFalse() {
- assertFalse(mDynamicDenylistManager.isInManualDenylist(FAKE_UID_1));
+ public void setUidPolicyLocked_invokeSetUidPolicy() {
+ initDynamicDenylistManager(EMPTY_ARRAY);
+
+ mDynamicDenylistManager.setUidPolicyLocked(FAKE_UID_1_INT,
+ POLICY_REJECT_METERED_BACKGROUND);
+
+ assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
+ verify(mNetworkPolicyManager).setUidPolicy(eq(FAKE_UID_1_INT),
+ eq(POLICY_REJECT_METERED_BACKGROUND));
}
@Test
- public void isManualDenylist_incorrectUid_returnsFalse() {
+ public void setDenylist_emptyListAndNoData_doNothing() {
+ initDynamicDenylistManager(EMPTY_ARRAY);
+
+ mDynamicDenylistManager.setDenylist(Collections.emptyList());
+
+ verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), anyInt());
+ }
+
+ @Test
+ public void setDenylist_uidDeniedAlready_doNothing()
+ throws PackageManager.NameNotFoundException {
+ when(mPackageManager.getPackageUid(anyString(), eq(0))).thenReturn(FAKE_UID_1_INT);
+ initDynamicDenylistManager(new int[]{FAKE_UID_1_INT});
+
+ mDynamicDenylistManager.setDenylist(List.of(FAKE_UID_1));
+
+ verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), anyInt());
+ }
+
+ @Test
+ public void setDenylist_sameList_doNothing() throws PackageManager.NameNotFoundException {
+ when(mPackageManager.getPackageUid(eq(FAKE_UID_1), eq(0))).thenReturn(FAKE_UID_1_INT);
+ when(mPackageManager.getPackageUid(eq(FAKE_UID_2), eq(0))).thenReturn(FAKE_UID_2_INT);
+ initDynamicDenylistManager(EMPTY_ARRAY);
+ setupPreference(mDynamicDenyListPref, FAKE_UID_2, FAKE_UID_1);
+
+ mDynamicDenylistManager.setDenylist(List.of(FAKE_UID_1, FAKE_UID_2));
+
+ verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), anyInt());
+ }
+
+ @Test
+ public void setDenylist_newListWithOldData_modifyPolicyNoneAndReject()
+ throws PackageManager.NameNotFoundException {
+ when(mPackageManager.getPackageUid(anyString(), eq(0))).thenReturn(
+ Integer.parseInt(FAKE_UID_1));
+ initDynamicDenylistManager(EMPTY_ARRAY);
+ setupPreference(mDynamicDenyListPref, FAKE_UID_2);
+
+ mDynamicDenylistManager.setDenylist(List.of(FAKE_UID_1));
+
+ verify(mNetworkPolicyManager).setUidPolicy(FAKE_UID_2_INT, POLICY_NONE);
+ verify(mNetworkPolicyManager).setUidPolicy(FAKE_UID_1_INT,
+ POLICY_REJECT_METERED_BACKGROUND);
+ assertThat(mDynamicDenyListPref.getAll()).hasSize(1);
+ assertTrue(mDynamicDenyListPref.contains(FAKE_UID_1));
+ }
+
+ @Test
+ public void setDenylist_newListWithoutOldData_modifyPolicyReject()
+ throws PackageManager.NameNotFoundException {
+ when(mPackageManager.getPackageUid(anyString(), eq(0))).thenReturn(
+ Integer.parseInt(FAKE_UID_1));
+ initDynamicDenylistManager(EMPTY_ARRAY);
+
+ mDynamicDenylistManager.setDenylist(List.of(FAKE_UID_1));
+
+ verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), eq(POLICY_NONE));
+ verify(mNetworkPolicyManager).setUidPolicy(FAKE_UID_1_INT,
+ POLICY_REJECT_METERED_BACKGROUND);
+ assertThat(mDynamicDenyListPref.getAll()).hasSize(1);
+ assertTrue(mDynamicDenyListPref.contains(FAKE_UID_1));
+ }
+
+ @Test
+ public void setDenylist_emptyListWithOldData_modifyPolicyNone() {
+ initDynamicDenylistManager(EMPTY_ARRAY);
+ setupPreference(mDynamicDenyListPref, FAKE_UID_2);
+
+ mDynamicDenylistManager.setDenylist(Collections.emptyList());
+
+ verify(mNetworkPolicyManager).setUidPolicy(FAKE_UID_2_INT, POLICY_NONE);
+ verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(),
+ eq(POLICY_REJECT_METERED_BACKGROUND));
+ assertThat(mDynamicDenyListPref.getAll()).isEmpty();
+ }
+
+ @Test
+ public void isInManualDenylist_returnsFalse() {
+ initDynamicDenylistManager(EMPTY_ARRAY);
+
+ assertFalse(mDynamicDenylistManager.isInManualDenylist(FAKE_UID_1_INT));
+ }
+
+ @Test
+ public void isInManualDenylist_incorrectUid_returnsFalse() {
+ initDynamicDenylistManager(EMPTY_ARRAY);
+
mManualDenyListPref.edit().putInt(FAKE_UID_2, POLICY_REJECT_METERED_BACKGROUND).apply();
- assertFalse(mDynamicDenylistManager.isInManualDenylist(FAKE_UID_1));
+ assertFalse(mDynamicDenylistManager.isInManualDenylist(FAKE_UID_1_INT));
}
@Test
- public void isManualDenylist_initiated_returnsTrue() {
+ public void isInManualDenylist_initiated_returnsTrue() {
+ initDynamicDenylistManager(EMPTY_ARRAY);
+
mManualDenyListPref.edit().putInt(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND).apply();
- assertTrue(mDynamicDenylistManager.isInManualDenylist(FAKE_UID_1));
+ assertTrue(mDynamicDenylistManager.isInManualDenylist(FAKE_UID_1_INT));
}
@Test
- public void clearManualDenylistPref_isEmpty() {
- mManualDenyListPref.edit().putInt(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND).apply();
+ public void resetDenylistIfNeeded_nullPackageName_doNothing() {
+ initDynamicDenylistManager(new int[0], new int[]{FAKE_UID_1_INT, FAKE_UID_2_INT});
+
+ mDynamicDenylistManager.resetDenylistIfNeeded(null, false);
+
assertThat(mManualDenyListPref.getAll()).hasSize(1);
- assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
+ verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), eq(POLICY_NONE));
+ }
- mDynamicDenylistManager.clearManualDenylistPref();
+ @Test
+ public void resetDenylistIfNeeded_invalidPackageName_doNothing() {
+ initDynamicDenylistManager(new int[0], new int[]{FAKE_UID_1_INT, FAKE_UID_2_INT});
+
+ mDynamicDenylistManager.resetDenylistIfNeeded("invalid_package_name", false);
+
+ assertThat(mManualDenyListPref.getAll()).hasSize(1);
+ verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), eq(POLICY_NONE));
+ }
+
+ @Test
+ public void resetDenylistIfNeeded_denylistUnchanged_doNothingWithPolicy() {
+ initDynamicDenylistManager(new int[]{FAKE_UID_1_INT, FAKE_UID_2_INT});
+
+ mDynamicDenylistManager.resetDenylistIfNeeded(SETTINGS_PACKAGE_NAME, false);
+
+ verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), eq(POLICY_NONE));
+ }
+
+ @Test
+ public void resetDenylistIfNeeded_denylistChanged_resetAndClear() {
+ initDynamicDenylistManager(new int[0], new int[]{FAKE_UID_1_INT, FAKE_UID_2_INT});
+
+ mDynamicDenylistManager.resetDenylistIfNeeded(SETTINGS_PACKAGE_NAME, false);
+
+ assertThat(mManualDenyListPref.getAll()).isEmpty();
+ verify(mNetworkPolicyManager, times(2)).setUidPolicy(anyInt(), eq(POLICY_NONE));
+ }
+
+ @Test
+ public void resetDenylistIfNeeded_forceResetWithNullPackageName_resetAndClear() {
+ initDynamicDenylistManager(new int[0], new int[]{FAKE_UID_2_INT});
+
+ mDynamicDenylistManager.resetDenylistIfNeeded(null, true);
+
+ assertThat(mManualDenyListPref.getAll()).isEmpty();
+ verify(mNetworkPolicyManager).setUidPolicy(eq(FAKE_UID_2_INT), eq(POLICY_NONE));
+ }
+
+ @Test// 4
+ public void resetDenylistIfNeeded_forceResetWithInvalidPackageName_resetAndClear() {
+ initDynamicDenylistManager(new int[0], new int[]{FAKE_UID_1_INT, FAKE_UID_2_INT});
+
+ mDynamicDenylistManager.resetDenylistIfNeeded("invalid_package_name", true);
+
+ assertThat(mManualDenyListPref.getAll()).isEmpty();
+ verify(mNetworkPolicyManager, times(2)).setUidPolicy(anyInt(), eq(POLICY_NONE));
+ }
+
+ @Test
+ public void resetDenylistIfNeeded_forceResetButDenylistUnchanged_doNothingWithPolicy() {
+ initDynamicDenylistManager(new int[]{FAKE_UID_1_INT});
+
+ mDynamicDenylistManager.resetDenylistIfNeeded(SETTINGS_PACKAGE_NAME, true);
+
+ assertThat(mManualDenyListPref.getAll()).isEmpty();
+ verify(mNetworkPolicyManager, never()).setUidPolicy(anyInt(), eq(POLICY_NONE));
+ }
+
+ @Test
+ public void resetDenylistIfNeeded_forceResetWithDenylistChanged_resetAndClear() {
+ initDynamicDenylistManager(new int[0], new int[]{FAKE_UID_1_INT, FAKE_UID_2_INT});
+
+ mDynamicDenylistManager.resetDenylistIfNeeded(SETTINGS_PACKAGE_NAME, true);
+
+ assertThat(mManualDenyListPref.getAll()).isEmpty();
+ verify(mNetworkPolicyManager, times(2)).setUidPolicy(anyInt(), eq(POLICY_NONE));
+ }
+
+ @Test
+ public void clearSharedPreferences_manualDenyListPrefIsEmpty() {
+ initDynamicDenylistManager(EMPTY_ARRAY);
+ mManualDenyListPref.edit().putInt(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND).apply();
+ assertThat(mManualDenyListPref.getAll()).hasSize(2);
+ assertTrue(mManualDenyListPref.contains(FAKE_UID_1));
+ assertTrue(mManualDenyListPref.contains(PREF_KEY_MANUAL_DENYLIST_SYNCED));
+
+ mDynamicDenylistManager.clearSharedPreferences();
assertThat(mManualDenyListPref.getAll()).isEmpty();
}
@Test
- public void clearDynamicDenylistPref_isEmpty() {
+ public void clearSharedPreferences_dynamicDenyListPrefIsEmpty() {
+ initDynamicDenylistManager(EMPTY_ARRAY);
mDynamicDenyListPref.edit().putInt(FAKE_UID_1, POLICY_REJECT_METERED_BACKGROUND).apply();
assertThat(mDynamicDenyListPref.getAll()).hasSize(1);
assertTrue(mDynamicDenyListPref.contains(FAKE_UID_1));
- mDynamicDenylistManager.clearDynamicDenylistPref();
+ mDynamicDenylistManager.clearSharedPreferences();
assertThat(mDynamicDenyListPref.getAll()).isEmpty();
}
+
+ private void initDynamicDenylistManager(int[] preload) {
+ initDynamicDenylistManager(preload, preload);
+ }
+ private void initDynamicDenylistManager(int[] preload1, int[] preload2) {
+ final Context context = spy(RuntimeEnvironment.application.getApplicationContext());
+ when(context.getApplicationContext()).thenReturn(context);
+ when(context.getPackageManager()).thenReturn(mPackageManager);
+ when(mNetworkPolicyManager.getUidsWithPolicy(anyInt()))
+ .thenReturn(preload1).thenReturn(preload2);
+ mDynamicDenylistManager = new DynamicDenylistManager(context, mNetworkPolicyManager);
+ mManualDenyListPref = mDynamicDenylistManager.getManualDenylistPref();
+ mDynamicDenyListPref = mDynamicDenylistManager.getDynamicDenylistPref();
+ }
+
+ private void setupPreference(SharedPreferences sharedPreferences, String... uids) {
+ for (String uid : uids) {
+ sharedPreferences.edit().putInt(uid, POLICY_REJECT_METERED_BACKGROUND).apply();
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/security/ContentProtectionPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/security/ContentProtectionPreferenceFragmentTest.java
index 3b5dbd6..d394582 100644
--- a/tests/robotests/src/com/android/settings/security/ContentProtectionPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/security/ContentProtectionPreferenceFragmentTest.java
@@ -113,8 +113,14 @@
final List<String> allKeys =
XmlTestUtils.getKeysFromPreferenceXml(
mContext, R.layout.content_protection_preference_fragment);
+ final List<String> nonIndexableKeysExpected =
+ List.of(
+ "content_protection_preference_top_intro",
+ "content_protection_preference_subpage_illustration",
+ "content_protection_preference_user_consent_work_profile_switch");
assertThat(allKeys).containsAtLeastElementsIn(nonIndexableKeys);
+ assertThat(nonIndexableKeys).isEqualTo(nonIndexableKeysExpected);
}
@Test
@@ -132,7 +138,7 @@
XmlTestUtils.getKeysFromPreferenceXml(
mContext, R.layout.content_protection_preference_fragment);
- assertThat(nonIndexableKeys).containsAnyIn(allKeys);
+ assertThat(nonIndexableKeys).isEqualTo(allKeys);
}
@Test
diff --git a/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java b/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java
index a402d91..8304e5d 100644
--- a/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java
+++ b/tests/unit/src/com/android/settings/development/graphicsdriver/GraphicsDriverEnableAngleAsSystemDriverControllerJUnitTest.java
@@ -20,7 +20,6 @@
import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.Injector;
import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.PROPERTY_DEBUG_ANGLE_DEVELOPER_OPTION;
import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.PROPERTY_PERSISTENT_GRAPHICS_EGL;
-import static com.android.settings.development.graphicsdriver.GraphicsDriverEnableAngleAsSystemDriverController.PROPERTY_RO_GFX_ANGLE_SUPPORTED;
import static com.google.common.truth.Truth.assertThat;
@@ -181,31 +180,13 @@
}
@Test
- public void updateState_angleNotSupported_PreferenceShouldDisabled() {
- when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any())).thenReturn("");
- mController.updateState(mPreference);
- assertThat(mPreference.isEnabled()).isFalse();
- }
-
- @Test
- public void updateState_angleNotSupported_PreferenceShouldNotBeChecked() {
- when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any())).thenReturn("");
- mController.updateState(mPreference);
- assertThat(mPreference.isChecked()).isFalse();
- }
-
- @Test
- public void updateState_angleSupported_PreferenceShouldEnabled() {
- when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
- .thenReturn("true");
+ public void updateState_PreferenceShouldEnabled() {
mController.updateState(mPreference);
assertThat(mPreference.isEnabled()).isTrue();
}
@Test
- public void updateState_angleSupported_angleIsSystemGLESDriver_PreferenceShouldBeChecked() {
- when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
- .thenReturn("true");
+ public void updateState_angleIsSystemGLESDriver_PreferenceShouldBeChecked() {
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
.thenReturn(ANGLE_DRIVER_SUFFIX);
mController.updateState(mPreference);
@@ -213,10 +194,7 @@
}
@Test
- public void
- updateState_angleSupported_angleIsNotSystemGLESDriver_PreferenceShouldNotBeChecked() {
- when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
- .thenReturn("true");
+ public void updateState_angleIsNotSystemGLESDriver_PreferenceShouldNotBeChecked() {
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any())).thenReturn("");
mController.updateState(mPreference);
assertThat(mPreference.isChecked()).isFalse();
@@ -232,8 +210,6 @@
// Test that onDeveloperOptionSwitchDisabled,
// persist.graphics.egl updates to ""
- when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
- .thenReturn("true");
mController.onDeveloperOptionsSwitchDisabled();
propertyChangeSignal1.wait(100);
final String systemEGLDriver = SystemProperties.get(PROPERTY_PERSISTENT_GRAPHICS_EGL);
@@ -245,16 +221,12 @@
@Test
public void onDeveloperOptionSwitchDisabled_PreferenceShouldNotBeChecked() {
- when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
- .thenReturn("true");
mController.onDeveloperOptionsSwitchDisabled();
assertThat(mPreference.isChecked()).isFalse();
}
@Test
public void onDeveloperOptionSwitchDisabled_PreferenceShouldDisabled() {
- when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
- .thenReturn("true");
mController.onDeveloperOptionsSwitchDisabled();
assertThat(mPreference.isEnabled()).isFalse();
}
@@ -480,8 +452,6 @@
// Test that when debug.graphics.angle.developeroption.enable is false:
when(mSystemPropertiesMock.getBoolean(eq(PROPERTY_DEBUG_ANGLE_DEVELOPER_OPTION),
anyBoolean())).thenReturn(false);
- when(mSystemPropertiesMock.get(eq(PROPERTY_RO_GFX_ANGLE_SUPPORTED), any()))
- .thenReturn("true");
// 1. "Enable ANGLE" switch is on, the switch should be enabled.
when(mSystemPropertiesMock.get(eq(PROPERTY_PERSISTENT_GRAPHICS_EGL), any()))
diff --git a/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java
new file mode 100644
index 0000000..0a2f3d1
--- /dev/null
+++ b/tests/unit/src/com/android/settings/privatespace/PrivateSpaceMaintainerTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.privatespace;
+
+import static com.android.settings.privatespace.PrivateSpaceMaintainer.HIDE_PRIVATE_SPACE_ENTRY_POINT_DISABLED_VAL;
+import static com.android.settings.privatespace.PrivateSpaceMaintainer.HIDE_PRIVATE_SPACE_ENTRY_POINT_ENABLED_VAL;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.privatespace.PrivateSpaceMaintainer.ErrorDeletingPrivateSpace;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class PrivateSpaceMaintainerTest {
+ private Context mContext;
+ private ContentResolver mContentResolver;
+
+ /** Required setup before a test. */
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = ApplicationProvider.getApplicationContext();
+ mContentResolver = mContext.getContentResolver();
+ }
+
+ /** Tests that {@link PrivateSpaceMaintainer#deletePrivateSpace()} deletes PS when PS exists. */
+ @Test
+ public void deletePrivateSpace_psExists_deletesPS() {
+ PrivateSpaceMaintainer privateSpaceMaintainer =
+ PrivateSpaceMaintainer.getInstance(mContext);
+ privateSpaceMaintainer.createPrivateSpace();
+ ErrorDeletingPrivateSpace errorDeletingPrivateSpace =
+ privateSpaceMaintainer.deletePrivateSpace();
+ assertThat(errorDeletingPrivateSpace)
+ .isEqualTo(ErrorDeletingPrivateSpace.DELETE_PS_ERROR_NONE);
+ assertThat(privateSpaceMaintainer.doesPrivateSpaceExist()).isFalse();
+ }
+
+ /**
+ * Tests that {@link PrivateSpaceMaintainer#deletePrivateSpace()} returns error when PS does
+ * not exist.
+ */
+ @Test
+ public void deletePrivateSpace_psDoesNotExist_returnsNoPSError() {
+ PrivateSpaceMaintainer privateSpaceMaintainer =
+ PrivateSpaceMaintainer.getInstance(mContext);
+ ErrorDeletingPrivateSpace errorDeletingPrivateSpace =
+ privateSpaceMaintainer.deletePrivateSpace();
+ assertThat(errorDeletingPrivateSpace)
+ .isEqualTo(ErrorDeletingPrivateSpace.DELETE_PS_ERROR_NO_PRIVATE_SPACE);
+ assertThat(privateSpaceMaintainer.doesPrivateSpaceExist()).isFalse();
+ }
+
+ /** Tests that {@link PrivateSpaceMaintainer#createPrivateSpace()} when PS exists creates PS. */
+ @Test
+ public void createPrivateSpace_psDoesNotExist_createsPS() {
+ PrivateSpaceMaintainer privateSpaceMaintainer =
+ PrivateSpaceMaintainer.getInstance(mContext);
+ privateSpaceMaintainer.deletePrivateSpace();
+ assertThat(privateSpaceMaintainer.createPrivateSpace()).isTrue();
+ assertThat(privateSpaceMaintainer.doesPrivateSpaceExist()).isTrue();
+ }
+
+ /**
+ * Tests that {@link PrivateSpaceMaintainer#createPrivateSpace()} when PS exists still
+ * returns true.
+ */
+ @Test
+ public void createPrivateSpace_psExists_returnsFalse() {
+ PrivateSpaceMaintainer privateSpaceMaintainer =
+ PrivateSpaceMaintainer.getInstance(mContext);
+ privateSpaceMaintainer.deletePrivateSpace();
+ assertThat(privateSpaceMaintainer.createPrivateSpace()).isTrue();
+ assertThat(privateSpaceMaintainer.doesPrivateSpaceExist()).isTrue();
+ assertThat(privateSpaceMaintainer.createPrivateSpace()).isTrue();
+ }
+
+ /**
+ * Tests that {@link PrivateSpaceMaintainer#createPrivateSpace()} when no PS exists resets PS
+ * Settings.
+ */
+ @Test
+ public void createPrivateSpace_psDoesNotExist_resetsPSSettings() {
+ PrivateSpaceMaintainer privateSpaceMaintainer =
+ PrivateSpaceMaintainer.getInstance(mContext);
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.HIDE_PRIVATESPACE_ENTRY_POINT,
+ HIDE_PRIVATE_SPACE_ENTRY_POINT_ENABLED_VAL);
+
+ privateSpaceMaintainer.deletePrivateSpace();
+ privateSpaceMaintainer.createPrivateSpace();
+ assertThat(privateSpaceMaintainer.getHidePrivateSpaceEntryPointSetting())
+ .isEqualTo(HIDE_PRIVATE_SPACE_ENTRY_POINT_DISABLED_VAL);
+ }
+
+ /**
+ * Tests that {@link PrivateSpaceMaintainer#createPrivateSpace()} when PS exist does not reset
+ * PS Settings.
+ */
+ @Test
+ public void createPrivateSpace_psExists_doesNotResetPSSettings() {
+ PrivateSpaceMaintainer privateSpaceMaintainer =
+ PrivateSpaceMaintainer.getInstance(mContext);
+ privateSpaceMaintainer.createPrivateSpace();
+ Settings.Secure.putInt(
+ mContentResolver,
+ Settings.Secure.HIDE_PRIVATESPACE_ENTRY_POINT,
+ HIDE_PRIVATE_SPACE_ENTRY_POINT_ENABLED_VAL);
+
+ privateSpaceMaintainer.createPrivateSpace();
+ assertThat(privateSpaceMaintainer.getHidePrivateSpaceEntryPointSetting())
+ .isEqualTo(HIDE_PRIVATE_SPACE_ENTRY_POINT_ENABLED_VAL);
+ }
+}