Merge "Renew the API getCallState" into main
diff --git a/aconfig/settings_flag_declarations.aconfig b/aconfig/settings_flag_declarations.aconfig
index c4c33b0..56c4b32 100644
--- a/aconfig/settings_flag_declarations.aconfig
+++ b/aconfig/settings_flag_declarations.aconfig
@@ -6,3 +6,10 @@
description: "This flag controls whether to show a Cancel button when factory reset"
bug: "300634367"
}
+
+flag {
+ name: "mainline_module_explicit_intent"
+ namespace: "android_settings"
+ description: "Enabling will provide an explicit package name for Intent to update mainline modules"
+ bug: "278987474"
+}
diff --git a/res/drawable/accessibility_text_reading_preview.xml b/res/drawable/accessibility_text_reading_preview.xml
index 040ccdf..1c9e752 100644
--- a/res/drawable/accessibility_text_reading_preview.xml
+++ b/res/drawable/accessibility_text_reading_preview.xml
@@ -20,5 +20,5 @@
android:shape="rectangle">
<corners android:radius="28dp" />
- <solid android:color="?androidprv:attr/materialColorSurfaceContainer" />
+ <solid android:color="@color/accessibility_text_reading_background" />
</shape>
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index 9334d19..a572841 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -69,6 +69,8 @@
<color name="udfps_enroll_progress_help">#607DA7F1</color>
<color name="udfps_enroll_progress_help_with_talkback">#FFEE675C</color>
+ <!-- Accessibility colors -->
+ <color name="accessibility_text_reading_background">@android:color/black</color>
<!-- Flash notifications colors -->
<!-- Screen flash notification color selected stroke in color selection dialog -->
<color name="screen_flash_color_button_outer_circle_stroke_color">#FFFFFF</color>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index f76f46e..03225a5 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -137,6 +137,8 @@
<color name="SIM_dark_mode_color_pink">#ffff8bcb</color> <!-- Material Pink 300 -->
<color name="SIM_dark_mode_color_orange">#fffcad70</color> <!-- Material Orange 300 -->
+ <!-- Accessibility colors -->
+ <color name="accessibility_text_reading_background">@android:color/white</color>
<!-- Accessibility Settings icon background colors -->
<color name="accessibility_feature_background">#5F6368</color> <!-- Google grey 700 -->
<color name="accessibility_magnification_background">#F50D60</color>
diff --git a/res/values/config.xml b/res/values/config.xml
old mode 100755
new mode 100644
index 7af29c8..73ee108
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -782,4 +782,7 @@
<item>@layout/screen_zoom_preview_1</item>
<item>@layout/accessibility_text_reading_preview_mail_content</item>
</array>
+
+ <!-- Package responsible for updating Mainline Modules -->
+ <string name="config_mainline_module_update_package" translatable="false">com.android.vending</string>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 52be658..6739a71 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5269,15 +5269,12 @@
<string name="accessibility_dialog_button_deny">Deny</string>
<!-- String for the allow button in accessibility permission dialog. [CHAR LIMIT=10] -->
- <string name="accessibility_dialog_button_stop">Stop</string>
+ <string name="accessibility_dialog_button_stop">Turn off</string>
<!-- String for the deny button in accessibility permission dialog. [CHAR LIMIT=10] -->
- <string name="accessibility_dialog_button_cancel">Cancel</string>
+ <string name="accessibility_dialog_button_cancel">Keep on</string>
<!-- Title for a warning about disabling an accessibility service. [CHAR LIMIT=NONE] -->
- <string name="disable_service_title">Stop <xliff:g id="service" example="TalkBack">%1$s</xliff:g>?</string>
- <!-- Message for a warning about disabling accessibility service. [CHAR LIMIT=NONE] -->
- <string name="disable_service_message">Tapping <xliff:g id="stop" example="Stop">%1$s</xliff:g> will
- stop <xliff:g id="service" example="TalkBack">%2$s</xliff:g>.</string>
+ <string name="disable_service_title">Turn off <xliff:g id="service" example="TalkBack">%1$s</xliff:g>?</string>
<!-- Title for the prompt shown as a placeholder if no accessibility services are installed. [CHAR LIMIT=50] -->
<string name="accessibility_no_services_installed">No services installed</string>
@@ -6540,6 +6537,11 @@
<!-- Dialog subtitle warning for a VPN app that has an insecure type. [CHAR LIMIT=100] -->
<string name="vpn_insecure_dialog_subtitle">Not secure. Update to an IKEv2 VPN</string>
+ <!-- Dialog message when user attempted to start a VPN type that is no longer supported. It is
+ very unlikely, but not impossible, that a user has a very old VPN configuration that the
+ newer device no longer supports. This message is displayed when the user tries to start
+ this unsupported VPN. [CHAR LIMIT=NONE] -->
+ <string name="vpn_start_unsupported">Failed to start unsupported VPN.</string>
<!-- Summary describing the always-on VPN feature. [CHAR LIMIT=NONE] -->
<string name="vpn_lockdown_summary">Select a VPN profile to always remain connected to. Network traffic will only be allowed when connected to this VPN.</string>
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 2113b5d..eeca139 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -42,7 +42,6 @@
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.content.pm.UserProperties;
import android.content.res.Configuration;
@@ -107,8 +106,6 @@
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceGroup;
import com.android.internal.app.UnlaunchableAppActivity;
import com.android.internal.util.ArrayUtils;
@@ -180,61 +177,6 @@
"delete_all_app_clones_enabled";
/**
- * Finds a matching activity for a preference's intent. If a matching
- * activity is not found, it will remove the preference.
- *
- * @param context The context.
- * @param parentPreferenceGroup The preference group that contains the
- * preference whose intent is being resolved.
- * @param preferenceKey The key of the preference whose intent is being
- * resolved.
- * @param flags 0 or one or more of
- * {@link #UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY}
- * .
- * @return Whether an activity was found. If false, the preference was
- * removed.
- */
- public static boolean updatePreferenceToSpecificActivityOrRemove(Context context,
- PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) {
-
- final Preference preference = parentPreferenceGroup.findPreference(preferenceKey);
- if (preference == null) {
- return false;
- }
-
- final Intent intent = preference.getIntent();
- if (intent != null) {
- // Find the activity that is in the system image
- final PackageManager pm = context.getPackageManager();
- final List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
- final int listSize = list.size();
- for (int i = 0; i < listSize; i++) {
- final ResolveInfo resolveInfo = list.get(i);
- if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
- != 0) {
-
- // Replace the intent with this specific activity
- preference.setIntent(new Intent().setClassName(
- resolveInfo.activityInfo.packageName,
- resolveInfo.activityInfo.name));
-
- if ((flags & UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY) != 0) {
- // Set the preference title to the activity's label
- preference.setTitle(resolveInfo.loadLabel(pm));
- }
-
- return true;
- }
- }
- }
-
- // Did not find a matching activity, so remove the preference
- parentPreferenceGroup.removePreference(preference);
-
- return false;
- }
-
- /**
* Returns true if Monkey is running.
*/
public static boolean isMonkeyRunning() {
diff --git a/src/com/android/settings/accessibility/AccessibilityServiceWarning.java b/src/com/android/settings/accessibility/AccessibilityServiceWarning.java
index 9022ebf..fb50ef1 100644
--- a/src/com/android/settings/accessibility/AccessibilityServiceWarning.java
+++ b/src/com/android/settings/accessibility/AccessibilityServiceWarning.java
@@ -139,9 +139,6 @@
return new AlertDialog.Builder(context)
.setTitle(context.getString(R.string.disable_service_title, serviceName))
- .setMessage(context.getString(R.string.disable_service_message,
- context.getString(R.string.accessibility_dialog_button_stop),
- serviceName))
.setCancelable(true)
.setPositiveButton(R.string.accessibility_dialog_button_stop, listener)
.setNegativeButton(R.string.accessibility_dialog_button_cancel, listener)
diff --git a/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java
index 5defe98..ccba9e7f 100644
--- a/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragment.java
@@ -25,6 +25,7 @@
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.ContentResolver;
+import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
@@ -37,17 +38,22 @@
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.widget.SettingsMainSwitchPreference;
import com.android.settingslib.search.SearchIndexable;
+import com.android.settingslib.search.SearchIndexableRaw;
import java.util.ArrayList;
import java.util.List;
-/** Settings page for color inversion. */
+/**
+ * Settings page for color inversion.
+ */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class ToggleColorInversionPreferenceFragment extends ToggleFeaturePreferenceFragment {
private static final String TAG = "ToggleColorInversionPreferenceFragment";
private static final String ENABLED = Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED;
+ private static final String KEY_SHORTCUT_PREFERENCE = "color_inversion_shortcut_key";
+
@Override
protected void registerKeysToObserverCallback(
AccessibilitySettingsContentObserver contentObserver) {
@@ -67,9 +73,9 @@
mHtmlDescription = getText(R.string.accessibility_display_inversion_preference_subtitle);
mTopIntroTitle = getText(R.string.accessibility_display_inversion_preference_intro_text);
mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
- .authority(getPrefContext().getPackageName())
- .appendPath(String.valueOf(R.raw.a11y_color_inversion_banner))
- .build();
+ .authority(getPrefContext().getPackageName())
+ .appendPath(String.valueOf(R.raw.a11y_color_inversion_banner))
+ .build();
final View view = super.onCreateView(inflater, container, savedInstanceState);
updateFooterPreference();
return view;
@@ -159,7 +165,7 @@
@Override
int getUserShortcutTypes() {
return AccessibilityUtil.getUserShortcutTypesFromSettings(getPrefContext(),
- mComponentName);
+ mComponentName);
}
@Override
@@ -170,8 +176,8 @@
@Override
CharSequence getTileTooltipContent(@QuickSettingsTooltipType int type) {
return getText(type == QuickSettingsTooltipType.GUIDE_TO_EDIT
- ? R.string.accessibility_color_inversion_qs_tooltip_content
- : R.string.accessibility_color_inversion_auto_added_qs_tooltip_content);
+ ? R.string.accessibility_color_inversion_qs_tooltip_content
+ : R.string.accessibility_color_inversion_auto_added_qs_tooltip_content);
}
@Override
@@ -184,5 +190,17 @@
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider(R.xml.accessibility_color_inversion_settings);
+ new BaseSearchIndexProvider(R.xml.accessibility_color_inversion_settings) {
+ @Override
+ public List<SearchIndexableRaw> getRawDataToIndex(Context context,
+ boolean enabled) {
+ final List<SearchIndexableRaw> rawData = new ArrayList<>();
+ SearchIndexableRaw raw = new SearchIndexableRaw(context);
+ raw.key = KEY_SHORTCUT_PREFERENCE;
+ raw.title = context.getString(
+ R.string.accessibility_display_inversion_shortcut_title);
+ rawData.add(raw);
+ return rawData;
+ }
+ };
}
diff --git a/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java b/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java
index 989be09..df30637 100644
--- a/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java
+++ b/src/com/android/settings/accounts/ManagedProfileQuietModeEnabler.java
@@ -16,6 +16,7 @@
package com.android.settings.accounts;
+import android.app.admin.flags.Flags;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -58,7 +59,14 @@
}
public void setQuietModeEnabled(boolean enabled) {
- if (mManagedProfile != null) {
+ if (mManagedProfile == null) {
+ return;
+ }
+ if (Flags.quietModeCredentialBugFix()) {
+ if (isQuietModeEnabled() != enabled) {
+ mUserManager.requestQuietModeEnabled(enabled, mManagedProfile);
+ }
+ } else {
mUserManager.requestQuietModeEnabled(enabled, mManagedProfile);
}
}
diff --git a/src/com/android/settings/accounts/WorkModePreferenceController.java b/src/com/android/settings/accounts/WorkModePreferenceController.java
index ae910f7..2aea27d 100644
--- a/src/com/android/settings/accounts/WorkModePreferenceController.java
+++ b/src/com/android/settings/accounts/WorkModePreferenceController.java
@@ -70,6 +70,9 @@
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
mQuietModeEnabler.setQuietModeEnabled(!isChecked);
+ if (android.app.admin.flags.Flags.quietModeCredentialBugFix()) {
+ updateState(mPreference);
+ }
}
@Override
diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
index 67d56e0..74a9673 100644
--- a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
+++ b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
@@ -53,7 +53,7 @@
* @see androidx.window.embedding.SplitController.SplitSupportStatus#SPLIT_UNAVAILABLE
*/
private static final boolean SHOULD_ENABLE_LARGE_SCREEN_OPTIMIZATION =
- SystemProperties.getBoolean("persist.settings.large_screen_opt.enabled", true);
+ SystemProperties.getBoolean("persist.settings.large_screen_opt.enabled", false);
private static final String TAG = "ActivityEmbeddingUtils";
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index a3dace6..3b162b6 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -353,15 +353,23 @@
}
LocalBluetoothProfile asha = mProfileManager.getHearingAidProfile();
+ LocalBluetoothProfile broadcastAssistant =
+ mProfileManager.getLeAudioBroadcastAssistantProfile();
for (CachedBluetoothDevice leAudioDevice : mProfileDeviceMap.get(profile.toString())) {
Log.d(TAG,
"device:" + leAudioDevice.getDevice().getAnonymizedAddress()
- + "disable LE profile");
+ + " disable LE profile");
profile.setEnabled(leAudioDevice.getDevice(), false);
if (asha != null) {
asha.setEnabled(leAudioDevice.getDevice(), true);
}
+ if (broadcastAssistant != null) {
+ Log.d(TAG,
+ "device:" + leAudioDevice.getDevice().getAnonymizedAddress()
+ + " disable LE broadcast assistant profile");
+ broadcastAssistant.setEnabled(leAudioDevice.getDevice(), false);
+ }
}
if (!SystemProperties.getBoolean(ENABLE_DUAL_MODE_AUDIO, false)) {
@@ -388,15 +396,23 @@
disableProfileBeforeUserEnablesLeAudio(mProfileManager.getHeadsetProfile());
}
LocalBluetoothProfile asha = mProfileManager.getHearingAidProfile();
+ LocalBluetoothProfile broadcastAssistant =
+ mProfileManager.getLeAudioBroadcastAssistantProfile();
for (CachedBluetoothDevice leAudioDevice : mProfileDeviceMap.get(profile.toString())) {
Log.d(TAG,
"device:" + leAudioDevice.getDevice().getAnonymizedAddress()
- + "enable LE profile");
+ + " enable LE profile");
profile.setEnabled(leAudioDevice.getDevice(), true);
if (asha != null) {
asha.setEnabled(leAudioDevice.getDevice(), false);
}
+ if (broadcastAssistant != null) {
+ Log.d(TAG,
+ "device:" + leAudioDevice.getDevice().getAnonymizedAddress()
+ + " enable LE broadcast assistant profile");
+ broadcastAssistant.setEnabled(leAudioDevice.getDevice(), true);
+ }
}
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
index 0d2b53a..1855667 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
@@ -49,6 +49,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -174,6 +175,13 @@
+ source
+ ", reason = "
+ reason);
+ AudioSharingUtils.toastMessage(
+ mContext,
+ String.format(
+ Locale.US,
+ "Fail to add source to %s reason %d",
+ sink.getAddress(),
+ reason));
}
@Override
@@ -209,6 +217,13 @@
+ sourceId
+ ", reason = "
+ reason);
+ AudioSharingUtils.toastMessage(
+ mContext,
+ String.format(
+ Locale.US,
+ "Fail to remove source from %s reason %d",
+ sink.getAddress(),
+ reason));
}
@Override
@@ -284,7 +299,7 @@
mPreferenceGroup.setVisible(false);
mAudioSharingSettingsPreference.setVisible(false);
- if (isAvailable()) {
+ if (isAvailable() && mBluetoothDeviceUpdater != null) {
mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
mBluetoothDeviceUpdater.forceUpdate();
}
@@ -379,8 +394,8 @@
// Show audio sharing switch or join dialog according to device count in the sharing
// session.
ArrayList<AudioSharingDeviceItem> deviceItemsInSharingSession =
- AudioSharingUtils.buildOrderedDeviceItemsInSharingSession(
- groupedDevices, mLocalBtManager);
+ AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem(
+ mLocalBtManager, groupedDevices, /* filterByInSharing= */ true);
// Show audio sharing switch dialog when the third eligible (LE audio) remote device
// connected during a sharing session.
if (deviceItemsInSharingSession.size() >= 2) {
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
index a0d44ff..53e095b 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingUtils.java
@@ -19,18 +19,22 @@
import android.bluetooth.BluetoothCsipSetCoordinator;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothLeBroadcastReceiveState;
+import android.content.Context;
import android.util.Log;
+import android.widget.Toast;
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 com.android.settingslib.utils.ThreadUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
public class AudioSharingUtils {
private static final String TAG = "AudioSharingUtils";
@@ -73,48 +77,102 @@
}
/**
- * Fetch a list of {@link AudioSharingDeviceItem}s in the audio sharing session.
+ * Fetch a list of ordered connected lead {@link CachedBluetoothDevice}s eligible for audio
+ * sharing. The active device is placed in the first place if it exists. The devices can be
+ * filtered by whether it is already in the audio sharing session.
*
+ * @param localBtManager The BT manager to provide BT functions. *
* @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.
+ * @param filterByInSharing Whether to filter the device by if is already in the sharing
+ * session.
+ * @return A list of ordered connected devices eligible for the audio sharing. The active device
+ * is placed in the first place if it exists.
*/
- public static ArrayList<AudioSharingDeviceItem> buildOrderedDeviceItemsInSharingSession(
+ public static ArrayList<CachedBluetoothDevice> buildOrderedConnectedLeadDevices(
+ LocalBluetoothManager localBtManager,
Map<Integer, List<CachedBluetoothDevice>> groupedConnectedDevices,
- LocalBluetoothManager localBtManager) {
- ArrayList<AudioSharingDeviceItem> deviceItems = new ArrayList<>();
+ boolean filterByInSharing) {
+ ArrayList<CachedBluetoothDevice> orderedDevices = new ArrayList<>();
LocalBluetoothLeBroadcastAssistant assistant =
localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
- if (assistant == null) return deviceItems;
- CachedBluetoothDevice activeDevice = null;
- List<CachedBluetoothDevice> inactiveDevices = new ArrayList<>();
+ if (assistant == null) return orderedDevices;
for (List<CachedBluetoothDevice> devices : groupedConnectedDevices.values()) {
+ CachedBluetoothDevice leadDevice = null;
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);
- }
+ if (!device.getMemberDevice().isEmpty()) {
+ leadDevice = device;
break;
}
}
+ if (leadDevice == null && !devices.isEmpty()) {
+ leadDevice = devices.get(0);
+ Log.d(
+ TAG,
+ "Empty member device, pick arbitrary device as the lead: "
+ + leadDevice.getDevice().getAnonymizedAddress());
+ }
+ if (leadDevice == null) {
+ Log.d(TAG, "Skip due to no lead device");
+ continue;
+ }
+ if (filterByInSharing && !hasBroadcastSource(leadDevice, localBtManager)) {
+ Log.d(
+ TAG,
+ "Filtered the device due to not in sharing session: "
+ + leadDevice.getDevice().getAnonymizedAddress());
+ continue;
+ }
+ orderedDevices.add(leadDevice);
}
- if (activeDevice != null) {
- deviceItems.add(buildAudioSharingDeviceItem(activeDevice));
- }
- inactiveDevices.stream()
- .sorted(CachedBluetoothDevice::compareTo)
- .forEach(
- device -> {
- deviceItems.add(buildAudioSharingDeviceItem(device));
- });
- return deviceItems;
+ orderedDevices.sort(
+ (CachedBluetoothDevice d1, CachedBluetoothDevice d2) -> {
+ // Active above not inactive
+ int comparison =
+ (isActiveLeAudioDevice(d2) ? 1 : 0)
+ - (isActiveLeAudioDevice(d1) ? 1 : 0);
+ if (comparison != 0) return comparison;
+ // Bonded above not bonded
+ comparison =
+ (d2.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0)
+ - (d1.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
+ if (comparison != 0) return comparison;
+ // Bond timestamp available above unavailable
+ comparison =
+ (d2.getBondTimestamp() != null ? 1 : 0)
+ - (d1.getBondTimestamp() != null ? 1 : 0);
+ if (comparison != 0) return comparison;
+ // Order by bond timestamp if it is available
+ // Otherwise order by device name
+ return d1.getBondTimestamp() != null
+ ? d1.getBondTimestamp().compareTo(d2.getBondTimestamp())
+ : d1.getName().compareTo(d2.getName());
+ });
+ return orderedDevices;
+ }
+
+ /**
+ * Fetch a list of ordered connected lead {@link AudioSharingDeviceItem}s eligible for audio
+ * sharing. The active device is placed in the first place if it exists. The devices can be
+ * filtered by whether it is already in the audio sharing session.
+ *
+ * @param localBtManager The BT manager to provide BT functions. *
+ * @param groupedConnectedDevices devices connected to broadcast assistant grouped by CSIP group
+ * id.
+ * @param filterByInSharing Whether to filter the device by if is already in the sharing
+ * session.
+ * @return A list of ordered connected devices eligible for the audio sharing. The active device
+ * is placed in the first place if it exists.
+ */
+ public static ArrayList<AudioSharingDeviceItem> buildOrderedConnectedLeadAudioSharingDeviceItem(
+ LocalBluetoothManager localBtManager,
+ Map<Integer, List<CachedBluetoothDevice>> groupedConnectedDevices,
+ boolean filterByInSharing) {
+ return buildOrderedConnectedLeadDevices(
+ localBtManager, groupedConnectedDevices, filterByInSharing)
+ .stream()
+ .map(device -> buildAudioSharingDeviceItem(device))
+ .collect(Collectors.toCollection(ArrayList::new));
}
/** Build {@link AudioSharingDeviceItem} from {@link CachedBluetoothDevice}. */
@@ -123,6 +181,57 @@
return new AudioSharingDeviceItem(
cachedDevice.getName(),
cachedDevice.getGroupId(),
- BluetoothUtils.isActiveLeAudioDevice(cachedDevice));
+ isActiveLeAudioDevice(cachedDevice));
+ }
+
+ /**
+ * Check if {@link CachedBluetoothDevice} is in an audio sharing session.
+ *
+ * @param cachedDevice The cached bluetooth device to check.
+ * @param localBtManager The BT manager to provide BT functions.
+ * @return Whether the device is in an audio sharing session.
+ */
+ public static boolean hasBroadcastSource(
+ CachedBluetoothDevice cachedDevice, LocalBluetoothManager localBtManager) {
+ LocalBluetoothLeBroadcastAssistant assistant =
+ localBtManager.getProfileManager().getLeAudioBroadcastAssistantProfile();
+ if (assistant == null) {
+ return false;
+ }
+ List<BluetoothLeBroadcastReceiveState> sourceList =
+ assistant.getAllSources(cachedDevice.getDevice());
+ if (!sourceList.isEmpty()) return true;
+ // Return true if member device is in broadcast.
+ for (CachedBluetoothDevice device : cachedDevice.getMemberDevice()) {
+ List<BluetoothLeBroadcastReceiveState> list =
+ assistant.getAllSources(device.getDevice());
+ if (!list.isEmpty()) return true;
+ }
+ return false;
+ }
+
+ /**
+ * Check if {@link CachedBluetoothDevice} is an active le audio device.
+ *
+ * @param cachedDevice The cached bluetooth device to check.
+ * @return Whether the device is an active le audio device.
+ */
+ public static boolean isActiveLeAudioDevice(CachedBluetoothDevice cachedDevice) {
+ if (BluetoothUtils.isActiveLeAudioDevice(cachedDevice)) {
+ return true;
+ }
+ // Return true if member device is an active le audio device.
+ for (CachedBluetoothDevice device : cachedDevice.getMemberDevice()) {
+ if (BluetoothUtils.isActiveLeAudioDevice(device)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Toast message on main thread. */
+ public static void toastMessage(Context context, String message) {
+ ThreadUtils.postOnMainThread(
+ () -> Toast.makeText(context, message, Toast.LENGTH_LONG).show());
}
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java
index a7d18e7..a6adf8a 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/CallsAndAlarmsPreferenceController.java
@@ -62,14 +62,6 @@
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- updateDeviceItemsInSharingSession();
- // mDeviceItemsInSharingSession is ordered. The active device is the first place if exits.
- if (!mDeviceItemsInSharingSession.isEmpty()
- && mDeviceItemsInSharingSession.get(0).isActive()) {
- mPreference.setSummary(mDeviceItemsInSharingSession.get(0).getName());
- } else {
- mPreference.setSummary("");
- }
mPreference.setOnPreferenceClickListener(
preference -> {
if (mFragment == null) {
@@ -107,6 +99,22 @@
}
@Override
+ public void updateVisibility(boolean isVisible) {
+ super.updateVisibility(isVisible);
+ if (isVisible && mPreference != null) {
+ updateDeviceItemsInSharingSession();
+ // mDeviceItemsInSharingSession is ordered. The active device is the first place if
+ // exits.
+ if (!mDeviceItemsInSharingSession.isEmpty()
+ && mDeviceItemsInSharingSession.get(0).isActive()) {
+ mPreference.setSummary(mDeviceItemsInSharingSession.get(0).getName());
+ } else {
+ mPreference.setSummary("");
+ }
+ }
+ }
+
+ @Override
public void onActiveDeviceChanged(
@Nullable CachedBluetoothDevice activeDevice, int bluetoothProfile) {
if (bluetoothProfile != BluetoothProfile.LE_AUDIO) {
@@ -129,7 +137,7 @@
mGroupedConnectedDevices =
AudioSharingUtils.fetchConnectedDevicesByGroupId(mLocalBtManager);
mDeviceItemsInSharingSession =
- AudioSharingUtils.buildOrderedDeviceItemsInSharingSession(
- mGroupedConnectedDevices, mLocalBtManager);
+ AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem(
+ mLocalBtManager, mGroupedConnectedDevices, /* filterByInSharing= */ true);
}
}
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java b/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java
index ec19e8d..d8e8887 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusDevicesController.java
@@ -108,10 +108,15 @@
return null;
}
- boolean doesStylusSupportTailButton = mInputDevice.hasKeys(
- KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL)[0];
- if (!doesStylusSupportTailButton) {
- return null;
+ // Check if the connected stylus supports the tail button. A connected device is when input
+ // device is available (mInputDevice != null). For a cached device (mInputDevice == null)
+ // there isn't way to check if the device supports the button so assume it does.
+ if (mInputDevice != null) {
+ boolean doesStylusSupportTailButton =
+ mInputDevice.hasKeys(KeyEvent.KEYCODE_STYLUS_BUTTON_TAIL)[0];
+ if (!doesStylusSupportTailButton) {
+ return null;
+ }
}
Preference pref = preference == null ? new Preference(mContext) : preference;
diff --git a/src/com/android/settings/dashboard/profileselector/UserAdapter.java b/src/com/android/settings/dashboard/profileselector/UserAdapter.java
index 66ba815..fa07ebc 100644
--- a/src/com/android/settings/dashboard/profileselector/UserAdapter.java
+++ b/src/com/android/settings/dashboard/profileselector/UserAdapter.java
@@ -59,7 +59,7 @@
mUserManager = um;
UserInfo userInfo = um.getUserInfo(mUserHandle.getIdentifier());
int tintColor = Utils.getColorAttrDefaultColor(context,
- com.android.internal.R.attr.materialColorPrimaryContainer);
+ com.android.internal.R.attr.materialColorPrimary);
if (userInfo.isManagedProfile()) {
mIcon = context.getPackageManager().getUserBadgeForDensityNoBackground(
userHandle, /* density= */ 0);
diff --git a/src/com/android/settings/development/quarantine/QuarantinedAppsScreenController.java b/src/com/android/settings/development/quarantine/QuarantinedAppsScreenController.java
index c3cb38d..4d4834b 100644
--- a/src/com/android/settings/development/quarantine/QuarantinedAppsScreenController.java
+++ b/src/com/android/settings/development/quarantine/QuarantinedAppsScreenController.java
@@ -18,6 +18,7 @@
import android.app.Application;
import android.content.Context;
+import android.content.pm.Flags;
import android.content.pm.PackageManager;
import android.content.pm.SuspendDialogInfo;
import android.os.UserHandle;
@@ -198,7 +199,7 @@
@Override
public int getAvailabilityStatus() {
- return AVAILABLE;
+ return Flags.quarantinedEnabled() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
@Override
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java
index fb17eca..39b8290 100644
--- a/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceController.java
@@ -28,6 +28,7 @@
import androidx.preference.Preference;
import com.android.settings.core.BasePreferenceController;
+import com.android.settings.flags.Flags;
import java.text.ParseException;
import java.text.SimpleDateFormat;
@@ -43,14 +44,15 @@
private static final String TAG = "MainlineModuleControl";
private static final List<String> VERSION_NAME_DATE_PATTERNS = Arrays.asList("yyyy-MM-dd",
"yyyy-MM");
-
@VisibleForTesting
- static final Intent MODULE_UPDATE_INTENT =
- new Intent("android.settings.MODULE_UPDATE_SETTINGS");
+ static final String MODULE_UPDATE_INTENT_ACTION =
+ "android.settings.MODULE_UPDATE_SETTINGS";
@VisibleForTesting
- static final Intent MODULE_UPDATE_V2_INTENT =
- new Intent("android.settings.MODULE_UPDATE_VERSIONS");
+ static final String MODULE_UPDATE_V2_INTENT_ACTION =
+ "android.settings.MODULE_UPDATE_VERSIONS";
+ private final Intent mModuleUpdateIntent;
+ private final Intent mModuleUpdateV2Intent;
private final PackageManager mPackageManager;
private String mModuleVersion;
@@ -58,6 +60,14 @@
public MainlineModuleVersionPreferenceController(Context context, String key) {
super(context, key);
mPackageManager = mContext.getPackageManager();
+ mModuleUpdateIntent = new Intent(MODULE_UPDATE_INTENT_ACTION);
+ mModuleUpdateV2Intent = new Intent(MODULE_UPDATE_V2_INTENT_ACTION);
+ if (Flags.mainlineModuleExplicitIntent()) {
+ String packageName = mContext
+ .getString(com.android.settings.R.string.config_mainline_module_update_package);
+ mModuleUpdateIntent.setPackage(packageName);
+ mModuleUpdateV2Intent.setPackage(packageName);
+ }
initModules();
}
@@ -86,17 +96,17 @@
super.updateState(preference);
final ResolveInfo resolvedV2 =
- mPackageManager.resolveActivity(MODULE_UPDATE_V2_INTENT, 0 /* flags */);
+ mPackageManager.resolveActivity(mModuleUpdateV2Intent, 0 /* flags */);
if (resolvedV2 != null) {
- preference.setIntent(MODULE_UPDATE_V2_INTENT);
+ preference.setIntent(mModuleUpdateV2Intent);
preference.setSelectable(true);
return;
}
final ResolveInfo resolved =
- mPackageManager.resolveActivity(MODULE_UPDATE_INTENT, 0 /* flags */);
+ mPackageManager.resolveActivity(mModuleUpdateIntent, 0 /* flags */);
if (resolved != null) {
- preference.setIntent(MODULE_UPDATE_INTENT);
+ preference.setIntent(mModuleUpdateIntent);
preference.setSelectable(true);
} else {
Log.d(TAG, "The ResolveInfo of the update intent is null.");
diff --git a/src/com/android/settings/inputmethod/SpellCheckerPreference.java b/src/com/android/settings/inputmethod/SpellCheckerPreference.java
index 116f1c7..8c8942a 100644
--- a/src/com/android/settings/inputmethod/SpellCheckerPreference.java
+++ b/src/com/android/settings/inputmethod/SpellCheckerPreference.java
@@ -47,6 +47,9 @@
super(context, null);
mScis = scis;
setWidgetLayoutResource(R.layout.preference_widget_gear);
+ if (scis == null) {
+ return;
+ }
CharSequence[] labels = new CharSequence[scis.length];
CharSequence[] values = new CharSequence[scis.length];
for (int i = 0 ; i < scis.length; i++) {
diff --git a/src/com/android/settings/inputmethod/SpellCheckersSettings.java b/src/com/android/settings/inputmethod/SpellCheckersSettings.java
index bcb527b..b4d7570 100644
--- a/src/com/android/settings/inputmethod/SpellCheckersSettings.java
+++ b/src/com/android/settings/inputmethod/SpellCheckersSettings.java
@@ -133,6 +133,7 @@
if (preference instanceof SpellCheckerPreference) {
final SpellCheckerPreference pref = (SpellCheckerPreference) preference;
pref.setSelected(mCurrentSci);
+ pref.setEnabled(mEnabledScis != null);
}
}
mSpellCheckerLanaguagePref.setEnabled(isSpellCheckerEnabled && mCurrentSci != null);
diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
index 2fcb06a..1b3a4f2 100644
--- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
+++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java
@@ -232,8 +232,7 @@
if (fromPosition != toPosition) {
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
- .action(mContext, SettingsEnums.ACTION_REORDER_LANGUAGE,
- mDragLocale.getLocale().toLanguageTag() + " move to " + toPosition);
+ .action(mContext, SettingsEnums.ACTION_REORDER_LANGUAGE);
}
notifyItemChanged(fromPosition); // to update the numbers
@@ -275,8 +274,7 @@
localeInfo = mFeedItemList.get(i);
if (localeInfo.getChecked()) {
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
- .action(mContext, SettingsEnums.ACTION_REMOVE_LANGUAGE,
- localeInfo.getLocale().toLanguageTag());
+ .action(mContext, SettingsEnums.ACTION_REMOVE_LANGUAGE);
mFeedItemList.remove(i);
}
}
diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java
index 59a39c8..1c22fd9 100644
--- a/src/com/android/settings/localepicker/LocaleListEditor.java
+++ b/src/com/android/settings/localepicker/LocaleListEditor.java
@@ -224,8 +224,7 @@
localeInfo = mayAppendUnicodeTags(localeInfo, preferencesTags);
mAdapter.addLocale(localeInfo);
updateVisibilityOfRemoveMenu();
- mMetricsFeatureProvider.action(getContext(), SettingsEnums.ACTION_ADD_LANGUAGE,
- localeInfo.getLocale().toLanguageTag());
+ mMetricsFeatureProvider.action(getContext(), SettingsEnums.ACTION_ADD_LANGUAGE);
} else if (requestCode == DIALOG_CONFIRM_SYSTEM_DEFAULT) {
localeInfo = mAdapter.getFeedItemList().get(0);
if (resultCode == Activity.RESULT_OK) {
@@ -239,8 +238,7 @@
localeDialogFragment.setArguments(args);
localeDialogFragment.show(mFragmentManager, TAG_DIALOG_NOT_AVAILABLE);
mMetricsFeatureProvider.action(getContext(),
- SettingsEnums.ACTION_NOT_SUPPORTED_SYSTEM_LANGUAGE,
- localeInfo.getLocale().toLanguageTag());
+ SettingsEnums.ACTION_NOT_SUPPORTED_SYSTEM_LANGUAGE);
}
} else {
mAdapter.notifyListChanged(localeInfo);
diff --git a/src/com/android/settings/network/apn/ApnEditPageProvider.kt b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
index 0ed54e7..86d7456 100644
--- a/src/com/android/settings/network/apn/ApnEditPageProvider.kt
+++ b/src/com/android/settings/network/apn/ApnEditPageProvider.kt
@@ -38,10 +38,13 @@
import com.android.settings.network.apn.ApnNetworkTypes.getNetworkTypeDisplayNames
import com.android.settings.network.apn.ApnNetworkTypes.getNetworkTypeSelectedOptionsState
import com.android.settingslib.spa.framework.common.SettingsPageProvider
+import com.android.settingslib.spa.framework.compose.LocalNavController
import com.android.settingslib.spa.widget.editor.SettingsExposedDropdownMenuBox
import com.android.settingslib.spa.widget.editor.SettingsExposedDropdownMenuCheckBox
import com.android.settingslib.spa.widget.editor.SettingsOutlinedTextField
import com.android.settingslib.spa.widget.editor.SettingsTextFieldPassword
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import com.android.settingslib.spa.widget.scaffold.RegularScaffold
@@ -199,6 +202,18 @@
emptyVal = stringResource(R.string.network_type_unspecified),
enabled = apnData.networkTypeEnabled
) {}
+ if (!apnData.newApn) {
+ val navController = LocalNavController.current
+ Preference(
+ object : PreferenceModel {
+ override val title = stringResource(R.string.menu_delete)
+ override val onClick = {
+ deleteApn(uriInit, context)
+ navController.navigateBack()
+ }
+ }
+ )
+ }
}
}
}
\ No newline at end of file
diff --git a/src/com/android/settings/network/apn/ApnStatus.kt b/src/com/android/settings/network/apn/ApnStatus.kt
index 3ccd71e..a479868 100644
--- a/src/com/android/settings/network/apn/ApnStatus.kt
+++ b/src/com/android/settings/network/apn/ApnStatus.kt
@@ -93,6 +93,12 @@
values.put(Telephony.Carriers.NETWORK_TYPE_BITMASK, networkType)
values.put(Telephony.Carriers.CARRIER_ENABLED, apnEnable)
values.put(Telephony.Carriers.EDITED_STATUS, Telephony.Carriers.USER_EDITED)
+ if (newApn) {
+ val simCarrierId =
+ context.getSystemService(TelephonyManager::class.java)!!.createForSubscriptionId(subId)
+ .getSimCarrierId()
+ values.put(Telephony.Carriers.CARRIER_ID, simCarrierId)
+ }
return values
}
}
@@ -513,4 +519,9 @@
APN_TYPE_IMS,
)
}.joinToString()
+}
+
+fun deleteApn(uri: Uri, context: Context) {
+ val contentResolver = context.contentResolver
+ contentResolver.delete(uri, null, null)
}
\ No newline at end of file
diff --git a/src/com/android/settings/regionalpreferences/NumberingSystemItemController.java b/src/com/android/settings/regionalpreferences/NumberingSystemItemController.java
index a608fbf..de0d386 100644
--- a/src/com/android/settings/regionalpreferences/NumberingSystemItemController.java
+++ b/src/com/android/settings/regionalpreferences/NumberingSystemItemController.java
@@ -153,7 +153,7 @@
private void handleLanguageSelect(Preference preference) {
String selectedLanguage = preference.getKey();
mMetricsFeatureProvider.action(mContext,
- SettingsEnums.ACTION_CHOOSE_LANGUAGE_FOR_NUMBERS_PREFERENCES, selectedLanguage);
+ SettingsEnums.ACTION_CHOOSE_LANGUAGE_FOR_NUMBERS_PREFERENCES);
final Bundle extra = new Bundle();
extra.putString(RegionalPreferencesEntriesFragment.ARG_KEY_REGIONAL_PREFERENCE,
ARG_VALUE_NUMBERING_SYSTEM_SELECT);
@@ -177,8 +177,7 @@
saveNumberingSystemToLocale(Locale.forLanguageTag(mSelectedLanguage),
numberingSystem);
mMetricsFeatureProvider.action(mContext,
- SettingsEnums.ACTION_SET_NUMBERS_PREFERENCES,
- updatedLocale.getDisplayName() + ": " + numberingSystem);
+ SettingsEnums.ACTION_SET_NUMBERS_PREFERENCES);
// After updated locale to framework, this fragment will recreate,
// so it needs to update the argument of selected language.
Bundle bundle = new Bundle();
diff --git a/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java b/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java
index ac0e7ee..8be0043 100644
--- a/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java
+++ b/src/com/android/settings/regionalpreferences/RegionalPreferenceListBasePreferenceController.java
@@ -16,6 +16,7 @@
package com.android.settings.regionalpreferences;
+import android.app.settings.SettingsEnums;
import android.content.Context;
import androidx.preference.PreferenceCategory;
@@ -65,8 +66,10 @@
RegionalPreferencesDataUtils.savePreference(mContext, getExtensionTypes(),
item.equals(RegionalPreferencesDataUtils.DEFAULT_VALUE)
? null : item);
- mMetricsFeatureProvider.action(mContext, getMetricsActionKey(),
- getPreferenceTitle(value) + " > " + getPreferenceTitle(item));
+ String metrics =
+ getMetricsActionKey() == SettingsEnums.ACTION_SET_FIRST_DAY_OF_WEEK ? ""
+ : getPreferenceTitle(value) + " > " + getPreferenceTitle(item);
+ mMetricsFeatureProvider.action(mContext, getMetricsActionKey(), metrics);
return true;
});
pref.setSelected(!value.isEmpty() && item.equals(value));
diff --git a/src/com/android/settings/system/SystemUpdatePreferenceController.kt b/src/com/android/settings/system/SystemUpdatePreferenceController.kt
index fa135aa..87a402e 100644
--- a/src/com/android/settings/system/SystemUpdatePreferenceController.kt
+++ b/src/com/android/settings/system/SystemUpdatePreferenceController.kt
@@ -28,7 +28,6 @@
import androidx.preference.Preference
import androidx.preference.PreferenceScreen
import com.android.settings.R
-import com.android.settings.Utils
import com.android.settings.core.BasePreferenceController
import com.android.settingslib.spaprivileged.framework.common.userManager
import kotlinx.coroutines.launch
@@ -36,6 +35,7 @@
open class SystemUpdatePreferenceController(context: Context, preferenceKey: String) :
BasePreferenceController(context, preferenceKey) {
private val userManager: UserManager = context.userManager
+ private val systemUpdateRepository = SystemUpdateRepository(context)
private val clientInitiatedActionRepository = ClientInitiatedActionRepository(context)
private lateinit var preference: Preference
@@ -48,12 +48,12 @@
super.displayPreference(screen)
preference = screen.findPreference(preferenceKey)!!
if (isAvailable) {
- Utils.updatePreferenceToSpecificActivityOrRemove(
- mContext,
- screen,
- preferenceKey,
- Utils.UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY,
- )
+ val intent = systemUpdateRepository.getSystemUpdateIntent()
+ if (intent != null) { // Replace the intent with this specific activity
+ preference.intent = intent
+ } else { // Did not find a matching activity, so remove the preference
+ screen.removePreference(preference)
+ }
}
}
diff --git a/src/com/android/settings/system/SystemUpdateRepository.kt b/src/com/android/settings/system/SystemUpdateRepository.kt
new file mode 100644
index 0000000..f8804be
--- /dev/null
+++ b/src/com/android/settings/system/SystemUpdateRepository.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.system
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.provider.Settings
+
+class SystemUpdateRepository(context: Context) {
+ private val packageManager = context.packageManager
+
+ /**
+ * Finds a matching activity for the system update intent.
+ */
+ fun getSystemUpdateIntent(): Intent? {
+ val intent = Intent(Settings.ACTION_SYSTEM_UPDATE_SETTINGS)
+ return packageManager.resolveActivity(intent, PackageManager.MATCH_SYSTEM_ONLY)
+ ?.activityInfo
+ ?.let { activityInfo ->
+ Intent().setClassName(activityInfo.packageName, activityInfo.name)
+ }
+ }
+}
diff --git a/src/com/android/settings/vpn2/ConfigDialogFragment.java b/src/com/android/settings/vpn2/ConfigDialogFragment.java
index 860fc4e..559003a 100644
--- a/src/com/android/settings/vpn2/ConfigDialogFragment.java
+++ b/src/com/android/settings/vpn2/ConfigDialogFragment.java
@@ -209,8 +209,8 @@
Toast.makeText(mContext, R.string.vpn_no_network, Toast.LENGTH_LONG).show();
} catch (UnsupportedOperationException e) {
Log.e(TAG, "Attempted to start an unsupported VPN type.");
- final AlertDialog dialog = new AlertDialog.Builder(mContext)
- .setMessage(R.string.vpn_insecure_dialog_subtitle)
+ final AlertDialog unusedDialog = new AlertDialog.Builder(mContext)
+ .setMessage(R.string.vpn_start_unsupported)
.setPositiveButton(android.R.string.ok, null)
.show();
}
diff --git a/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java b/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java
index 81c44df..305b03a 100644
--- a/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/ManagedProfileQuietModeEnablerTest.java
@@ -19,18 +19,22 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
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.app.admin.flags.Flags;
import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
+import android.platform.test.annotations.RequiresFlagsEnabled;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
@@ -42,13 +46,15 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
+import org.robolectric.ParameterizedRobolectricTestRunner;
import org.robolectric.annotation.LooperMode;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
-@RunWith(RobolectricTestRunner.class)
+@RunWith(ParameterizedRobolectricTestRunner.class)
@LooperMode(LooperMode.Mode.LEGACY)
public class ManagedProfileQuietModeEnablerTest {
private static final int MANAGED_USER_ID = 10;
@@ -63,6 +69,12 @@
}
};
+ @ParameterizedRobolectricTestRunner.Parameters
+ public static List<?> params() {
+ return Arrays.asList(true, false);
+ }
+ final boolean mEnable;
+
@Mock
private ManagedProfileQuietModeEnabler.QuietModeChangeListener mOnQuietModeChangeListener;
@Mock
@@ -72,6 +84,10 @@
@Mock
private UserInfo mUserInfo;
+ public ManagedProfileQuietModeEnablerTest(boolean enable) {
+ mEnable = enable;
+ }
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -88,10 +104,21 @@
@Test
public void onSetQuietMode_shouldRequestQuietModeEnabled() {
- mQuietModeEnabler.setQuietModeEnabled(false);
- verify(mUserManager).requestQuietModeEnabled(false, mManagedUser);
- mQuietModeEnabler.setQuietModeEnabled(true);
- verify(mUserManager).requestQuietModeEnabled(true, mManagedUser);
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(!mEnable);
+
+ mQuietModeEnabler.setQuietModeEnabled(mEnable);
+
+ verify(mUserManager).requestQuietModeEnabled(mEnable, mManagedUser);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_QUIET_MODE_CREDENTIAL_BUG_FIX)
+ public void onSetQuietMode_ifQuietModeAlreadyInDesiredState_shouldNotRequestQuietModeEnabled() {
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(mEnable);
+
+ mQuietModeEnabler.setQuietModeEnabled(mEnable);
+
+ verify(mUserManager, never()).requestQuietModeEnabled(anyBoolean(), any());
}
@Test
@@ -107,6 +134,7 @@
Intent.EXTRA_USER_HANDLE, MANAGED_USER_ID));
mContext.sendBroadcast(new Intent(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE).putExtra(
Intent.EXTRA_USER_HANDLE, MANAGED_USER_ID));
+
verify(mOnQuietModeChangeListener, times(2)).onQuietModeChanged();
}
@@ -123,6 +151,7 @@
Context.RECEIVER_EXPORTED/*UNAUDITED*/);
mQuietModeEnabler.onStop(mLifecycleOwner);
+
verify(mContext).unregisterReceiver(mQuietModeEnabler.mReceiver);
}
}
diff --git a/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java
index e53ed10..8b4ebca 100644
--- a/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java
@@ -40,9 +40,12 @@
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.ParameterizedRobolectricTestRunner;
import org.robolectric.RobolectricTestRunner;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class WorkModePreferenceControllerTest {
@@ -54,6 +57,11 @@
private WorkModePreferenceController mController;
private MainSwitchPreference mPreference;
+ @ParameterizedRobolectricTestRunner.Parameters
+ public static List<?> params() {
+ return Arrays.asList(true, false);
+ }
+ final boolean mEnable;
@Mock
private UserManager mUserManager;
@Mock
@@ -65,6 +73,10 @@
@Mock
Switch mSwitch;
+ public WorkModePreferenceControllerTest(boolean enable) {
+ mEnable = enable;
+ }
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
@@ -99,28 +111,19 @@
@Test
public void updateState_shouldRefreshContent() {
when(mUserManager.isQuietModeEnabled(any(UserHandle.class)))
- .thenReturn(false);
+ .thenReturn(mEnable);
mController.updateState(mPreference);
- assertThat(mPreference.isChecked()).isTrue();
-
- when(mUserManager.isQuietModeEnabled(any(UserHandle.class)))
- .thenReturn(true);
-
- mController.updateState(mPreference);
-
- assertThat(mPreference.isChecked()).isFalse();
+ assertThat(mPreference.isChecked()).isEqualTo(!mEnable);
}
@Test
public void onPreferenceChange_shouldRequestQuietModeEnabled() {
- mController.onCheckedChanged(mSwitch, true);
+ when(mUserManager.isQuietModeEnabled(any(UserHandle.class))).thenReturn(mEnable);
- verify(mUserManager).requestQuietModeEnabled(false, mManagedUser);
+ mController.onCheckedChanged(mSwitch, mEnable);
- mController.onCheckedChanged(mSwitch, false);
-
- verify(mUserManager).requestQuietModeEnabled(true, mManagedUser);
+ verify(mUserManager).requestQuietModeEnabled(!mEnable, mManagedUser);
}
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java b/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
index 78cfd36..85d1b78 100644
--- a/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
+++ b/tests/robotests/src/com/android/settings/applications/InstalledAppCounterTest.java
@@ -98,7 +98,7 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
mFakeFeatureFlags = new FakeFeatureFlagsImpl();
mFakeFeatureFlags.setFlag(Flags.FLAG_ARCHIVING, true);
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java
index 047a7d5..a540d28 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/stylus/StylusDevicesControllerTest.java
@@ -54,7 +54,7 @@
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
+import androidx.preference.SwitchPreferenceCompat;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
@@ -518,7 +518,8 @@
Settings.Secure.STYLUS_BUTTONS_ENABLED, 0);
showScreen(mController);
- SwitchPreference buttonsPref = (SwitchPreference) mPreferenceContainer.getPreference(2);
+ SwitchPreferenceCompat buttonsPref =
+ (SwitchPreferenceCompat) mPreferenceContainer.getPreference(2);
assertThat(buttonsPref.isChecked()).isEqualTo(true);
}
@@ -529,7 +530,8 @@
Settings.Secure.STYLUS_BUTTONS_ENABLED, 1);
showScreen(mController);
- SwitchPreference buttonsPref = (SwitchPreference) mPreferenceContainer.getPreference(2);
+ SwitchPreferenceCompat buttonsPref =
+ (SwitchPreferenceCompat) mPreferenceContainer.getPreference(2);
assertThat(buttonsPref.isChecked()).isEqualTo(false);
}
@@ -539,7 +541,8 @@
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.STYLUS_BUTTONS_ENABLED, 0);
showScreen(mController);
- SwitchPreference buttonsPref = (SwitchPreference) mPreferenceContainer.getPreference(2);
+ SwitchPreferenceCompat buttonsPref =
+ (SwitchPreferenceCompat) mPreferenceContainer.getPreference(2);
buttonsPref.performClick();
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java
index 9129906..a326061 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/firmwareversion/MainlineModuleVersionPreferenceControllerTest.java
@@ -18,8 +18,8 @@
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
-import static com.android.settings.deviceinfo.firmwareversion.MainlineModuleVersionPreferenceController.MODULE_UPDATE_INTENT;
-import static com.android.settings.deviceinfo.firmwareversion.MainlineModuleVersionPreferenceController.MODULE_UPDATE_V2_INTENT;
+import static com.android.settings.deviceinfo.firmwareversion.MainlineModuleVersionPreferenceController.MODULE_UPDATE_INTENT_ACTION;
+import static com.android.settings.deviceinfo.firmwareversion.MainlineModuleVersionPreferenceController.MODULE_UPDATE_V2_INTENT_ACTION;
import static com.google.common.truth.Truth.assertThat;
@@ -29,13 +29,18 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.preference.Preference;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -46,6 +51,15 @@
@RunWith(RobolectricTestRunner.class)
public class MainlineModuleVersionPreferenceControllerTest {
+ private static final String MODULE_PACKAGE = "com.android.vending";
+ private static final Intent MODULE_UPDATE_V2_INTENT =
+ new Intent(MODULE_UPDATE_V2_INTENT_ACTION).setPackage(MODULE_PACKAGE);
+ private static final Intent MODULE_UPDATE_INTENT =
+ new Intent(MODULE_UPDATE_INTENT_ACTION).setPackage(MODULE_PACKAGE);
+
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
@Mock
private PackageManager mPackageManager;
@@ -58,6 +72,9 @@
mContext = spy(RuntimeEnvironment.application);
mPreference = new Preference(mContext);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
+ when(mContext
+ .getString(com.android.settings.R.string.config_mainline_module_update_package))
+ .thenReturn(MODULE_PACKAGE);
}
@Test
@@ -123,6 +140,7 @@
assertThat(mPreference.isSelectable()).isTrue();
}
+ @RequiresFlagsEnabled(com.android.settings.flags.Flags.FLAG_MAINLINE_MODULE_EXPLICIT_INTENT)
@Test
public void updateState_canHandleIntent_setIntentToPreference() throws Exception {
setupModulePackage("test version 123");
@@ -137,6 +155,7 @@
assertThat(mPreference.getIntent()).isEqualTo(MODULE_UPDATE_INTENT);
}
+ @RequiresFlagsEnabled(com.android.settings.flags.Flags.FLAG_MAINLINE_MODULE_EXPLICIT_INTENT)
@Test
public void updateState_canHandleIntent_preferenceShouldBeSelectable() throws Exception {
setupModulePackage("test version 123");
@@ -151,6 +170,7 @@
assertThat(mPreference.isSelectable()).isTrue();
}
+ @RequiresFlagsEnabled(com.android.settings.flags.Flags.FLAG_MAINLINE_MODULE_EXPLICIT_INTENT)
@Test
public void updateState_cannotHandleIntent_setNullToPreference() throws Exception {
setupModulePackage("test version 123");
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/legal/ModuleLicensePreferenceTest.java b/tests/robotests/src/com/android/settings/deviceinfo/legal/ModuleLicensePreferenceTest.java
index 08eec9e..1352402 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/legal/ModuleLicensePreferenceTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/legal/ModuleLicensePreferenceTest.java
@@ -24,7 +24,6 @@
import android.content.pm.ModuleInfo;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
@@ -57,7 +56,6 @@
}
@Test
- @Ignore
public void onClick_sendsCorrectIntent() {
ModuleLicensePreference pref = new ModuleLicensePreference(mContext, mModuleInfo);
@@ -69,7 +67,7 @@
.isEqualTo(ModuleLicenseProvider.getUriForPackage(PACKAGE_NAME));
assertThat(intent.getType()).isEqualTo(ModuleLicenseProvider.LICENSE_FILE_MIME_TYPE);
assertThat(intent.getCharSequenceExtra(Intent.EXTRA_TITLE)).isEqualTo(NAME);
- assertThat(intent.getFlags()).isEqualTo(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ assertThat((intent.getFlags() & Intent.FLAG_GRANT_READ_URI_PERMISSION)).isNotEqualTo(0);
assertThat(intent.getCategories()).contains(Intent.CATEGORY_DEFAULT);
assertThat(intent.getPackage()).isEqualTo("com.android.htmlviewer");
}
diff --git a/tests/spa_unit/src/com/android/settings/system/SystemUpdateRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/system/SystemUpdateRepositoryTest.kt
new file mode 100644
index 0000000..ea4617a
--- /dev/null
+++ b/tests/spa_unit/src/com/android/settings/system/SystemUpdateRepositoryTest.kt
@@ -0,0 +1,80 @@
+/*
+ * 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.system
+
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
+import android.provider.Settings
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.kotlin.argThat
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
+
+@RunWith(AndroidJUnit4::class)
+class SystemUpdateRepositoryTest {
+ private val mockPackageManager = mock<PackageManager>()
+
+ private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
+ on { packageManager } doReturn mockPackageManager
+ }
+
+ private val repository = SystemUpdateRepository(context)
+
+ @Test
+ fun getSystemUpdateIntent_noResolveActivity_returnNull() {
+ val intent = repository.getSystemUpdateIntent()
+
+ assertThat(intent).isNull()
+ }
+
+ @Test
+ fun getSystemUpdateIntent_hasResolveActivity_returnIntent() {
+ mockPackageManager.stub {
+ on {
+ resolveActivity(
+ argThat { action == Settings.ACTION_SYSTEM_UPDATE_SETTINGS },
+ eq(PackageManager.MATCH_SYSTEM_ONLY),
+ )
+ } doReturn RESOLVE_INFO
+ }
+
+ val intent = repository.getSystemUpdateIntent()
+
+ assertThat(intent?.component?.packageName).isEqualTo(PACKAGE_NAME)
+ assertThat(intent?.component?.className).isEqualTo(ACTIVITY_NAME)
+ }
+
+ private companion object {
+ const val PACKAGE_NAME = "package.name"
+ const val ACTIVITY_NAME = "ActivityName"
+ val RESOLVE_INFO = ResolveInfo().apply {
+ activityInfo = ActivityInfo().apply {
+ packageName = PACKAGE_NAME
+ name = ACTIVITY_NAME
+ }
+ }
+ }
+}
diff --git a/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java b/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java
index 5c42ad9..50e21fe 100644
--- a/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java
+++ b/tests/unit/src/com/android/settings/regionalpreferences/NumberingSystemItemControllerTest.java
@@ -99,8 +99,7 @@
assertTrue(isCallingStartActivity);
verify(mFeatureFactory.metricsFeatureProvider).action(
mApplicationContext,
- SettingsEnums.ACTION_CHOOSE_LANGUAGE_FOR_NUMBERS_PREFERENCES,
- "I_am_the_key");
+ SettingsEnums.ACTION_CHOOSE_LANGUAGE_FOR_NUMBERS_PREFERENCES);
}
@Test
@@ -122,8 +121,7 @@
verify(mFragment).setArguments(any());
verify(mFeatureFactory.metricsFeatureProvider).action(
- mApplicationContext, SettingsEnums.ACTION_SET_NUMBERS_PREFERENCES,
- "test_key");
+ mApplicationContext, SettingsEnums.ACTION_SET_NUMBERS_PREFERENCES);
}
@Test