Merge "Fix going back after biometric enrollment in SUW" into udc-dev
diff --git a/res/drawable/ic_enterprise.xml b/res/drawable/ic_enterprise.xml
index c2d9df6..231f706 100644
--- a/res/drawable/ic_enterprise.xml
+++ b/res/drawable/ic_enterprise.xml
@@ -17,9 +17,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
+ android:viewportWidth="960"
+ android:viewportHeight="960">
<path
- android:pathData="M20,6h-4L16,4c0,-1.11 -0.89,-2 -2,-2h-4c-1.11,0 -2,0.89 -2,2v2L4,6c-1.11,0 -1.99,0.89 -1.99,2L2,19c0,1.11 0.89,2 2,2h16c1.11,0 2,-0.89 2,-2L22,8c0,-1.11 -0.89,-2 -2,-2zM12,15c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM14,6h-4L10,4h4v2z"
+ android:pathData="M140,840Q116,840 98,822Q80,804 80,780L80,300Q80,276 98,258Q116,240 140,240L320,240L320,140Q320,116 338,98Q356,80 380,80L580,80Q604,80 622,98Q640,116 640,140L640,240L820,240Q844,240 862,258Q880,276 880,300L880,780Q880,804 862,822Q844,840 820,840L140,840ZM380,240L580,240L580,140Q580,140 580,140Q580,140 580,140L380,140Q380,140 380,140Q380,140 380,140L380,240Z"
android:fillColor="?android:attr/colorPrimary"/>
</vector>
\ No newline at end of file
diff --git a/res/drawable/ic_stylus.xml b/res/drawable/ic_stylus.xml
new file mode 100644
index 0000000..eb52fec
--- /dev/null
+++ b/res/drawable/ic_stylus.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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.
+ -->
+
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?android:attr/colorControlNormal">
+ <path android:fillColor="@android:color/white"
+ android:pathData="M167,840Q146,845 130.5,829.5Q115,814 120,793L160,602L358,800L167,840ZM358,800L160,602L618,144Q641,121 675,121Q709,121 732,144L816,228Q839,251 839,285Q839,319 816,342L358,800ZM675,200L261,614L346,699L760,285Q760,285 760,285Q760,285 760,285L675,200Q675,200 675,200Q675,200 675,200Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml b/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml
deleted file mode 100644
index 11bb0ae..0000000
--- a/res/layout-land/wifi_dpp_qrcode_scanner_fragment.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- 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.
--->
-
-<com.google.android.setupdesign.GlifLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:icon="@drawable/ic_scan_32dp"
- app:sudDescriptionText="@string/wifi_dpp_scan_qr_code_join_unknown_network">
-
- <LinearLayout
- style="@style/SudContentFrame"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical">
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:orientation="vertical">
-
- <FrameLayout
- android:layout_width="@dimen/qrcode_preview_size"
- android:layout_height="@dimen/qrcode_preview_size"
- android:clipChildren="true">
- <TextureView
- android:id="@+id/preview_view"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"/>
- <com.android.settingslib.qrcode.QrDecorateView
- android:id="@+id/decorate_view"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"/>
- </FrameLayout>
-
- <TextView
- android:id="@+id/error_message"
- style="@style/TextAppearance.ErrorText"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="16dp"
- android:layout_marginStart="?attr/sudMarginStart"
- android:layout_marginEnd="?attr/sudMarginEnd"
- android:textAlignment="center"
- android:visibility="invisible"/>
-
- </LinearLayout>
-
- </LinearLayout>
-
-</com.google.android.setupdesign.GlifLayout>
-
diff --git a/res/layout/dream_preference_layout.xml b/res/layout/dream_preference_layout.xml
index aff8ad3..05b7b6e 100644
--- a/res/layout/dream_preference_layout.xml
+++ b/res/layout/dream_preference_layout.xml
@@ -79,6 +79,7 @@
android:textSize="@dimen/dream_item_title_text_size"
android:textColor="@color/dream_card_text_color_state_list"
android:drawablePadding="@dimen/dream_item_icon_padding"
+ android:drawableTint="@color/dream_card_icon_color_state_list"
app:layout_constraintTop_toBottomOf="@+id/preview"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
diff --git a/res/layout/wifi_dpp_qrcode_scanner_fragment.xml b/res/layout/wifi_dpp_qrcode_scanner_fragment.xml
index dd96d7e..84470ba 100644
--- a/res/layout/wifi_dpp_qrcode_scanner_fragment.xml
+++ b/res/layout/wifi_dpp_qrcode_scanner_fragment.xml
@@ -36,19 +36,31 @@
android:gravity="center"
android:orientation="vertical">
- <FrameLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:clipChildren="true">
- <TextureView
- android:id="@+id/preview_view"
- android:layout_width="match_parent"
- android:layout_height="@dimen/qrcode_preview_size"/>
- <com.android.settingslib.qrcode.QrDecorateView
- android:id="@+id/decorate_view"
- android:layout_width="match_parent"
- android:layout_height="@dimen/qrcode_preview_size"/>
- </FrameLayout>
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:maxWidth="@dimen/qrcode_preview_size"
+ android:maxHeight="@dimen/qrcode_preview_size">
+
+ <FrameLayout
+ android:layout_width="0dp"
+ android:layout_height="0dp"
+ app:layout_constraintDimensionRatio="1:1"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ android:clipChildren="true">
+ <TextureView
+ android:id="@+id/preview_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ <com.android.settingslib.qrcode.QrDecorateView
+ android:id="@+id/decorate_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ </FrameLayout>
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/error_message"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 261829b..b12f390 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -221,14 +221,17 @@
<!-- UI debug setting: Disable Bluetooth hardware offload [CHAR LIMIT=none] -->
<string name="bluetooth_disable_hw_offload_dialog_cancel">Cancel</string>
- <!-- Setting Checkbox title for disabling Bluetooth LE Audio feature. [CHAR LIMIT=40] -->
+ <!-- Setting toggle title for disabling Bluetooth LE Audio feature. [CHAR LIMIT=40] -->
<string name="bluetooth_disable_leaudio">Disable Bluetooth LE audio</string>
- <!-- Summary of checkbox for disabling Bluetooth LE audio [CHAR LIMIT=none]-->
+ <!-- Summary of toggle for disabling Bluetooth LE audio [CHAR LIMIT=none]-->
<string name="bluetooth_disable_leaudio_summary">Disables Bluetooth LE audio feature if the device supports LE audio hardware capabilities.</string>
- <!-- Setting Checkbox title for enabling Bluetooth LE Audio Allow List. [CHAR LIMIT=none] -->
+ <!-- Setting toggle title for enabling Bluetooth LE Audio toggle in Device Details. [CHAR LIMIT=40] -->
+ <string name="bluetooth_show_leaudio_device_details">Show LE audio toggle in Device Details</string>
+
+ <!-- Setting toggle title for enabling Bluetooth LE Audio Allow List. [CHAR LIMIT=none] -->
<string name="bluetooth_enable_leaudio_allow_list">Enable Bluetooth LE audio Allow List</string>
- <!-- Summary of checkbox for enabling Bluetooth LE audio Allow List [CHAR LIMIT=none]-->
+ <!-- Summary of toggle for enabling Bluetooth LE audio Allow List [CHAR LIMIT=none]-->
<string name="bluetooth_enable_leaudio_allow_list_summary">Enable Bluetooth LE audio allow list feature.</string>
<!-- Title for Bluetooth device group with media capability group [CHAR LIMIT=none]-->
@@ -815,6 +818,10 @@
<string name="biometric_settings_intro_with_fingerprint">You can unlock with your watch when your fingerprint isn\u2019t recognized.</string>
<!-- Introduction shown in face page to explain that watch unlock can be used if face isn't recognized. [CHAR LIMIT=NONE]-->
<string name="biometric_settings_intro_with_face">You can unlock with your watch when your face isn\u2019t recognized.</string>
+ <string name="biometric_settings_use_fingerprint_or_watch_for"> Use fingerprint or watch to</string>
+ <string name="biometric_settings_use_face_or_watch_for"> Use face or watch to</string>
+ <string name="biometric_settings_use_face_fingerprint_or_watch_for"> Use face, fingerprint, or watch to</string>
+ <string name="biometric_settings_use_watch_for"> Use watch to</string>
<!-- Message for a biometric preference toggle, indicating that an action can only be performed by using Face Unlock or Watch Unlock. [CHAR LIMIT=50] -->
<string name="biometric_settings_use_face_or_watch_preference_summary">Using face or watch</string>
<!-- Message for a biometric preference toggle, indicating that an action can only be performed by using Fingerprint Unlock or Watch Unlock. [CHAR LIMIT=50] -->
@@ -5172,7 +5179,7 @@
<!-- Title for the battery limited temporarily tip [CHAR LIMIT=NONE] -->
<string name="battery_tip_limited_temporarily_title">Charging optimized to protect your battery</string>
<!-- Summary for the battery limited temporarily tip [CHAR LIMIT=NONE] -->
- <string name="battery_tip_limited_temporarily_summary">To help extend your batter\'s lifespan, charging is optimized</string>
+ <string name="battery_tip_limited_temporarily_summary">To help extend your battery\'s lifespan, charging is optimized</string>
<!-- Title for the battery dock defender future bypass tip [CHAR LIMIT=NONE] -->
<string name="battery_tip_dock_defender_future_bypass_title">Charging optimized to protect your battery</string>
<!-- Summary for the battery dock defender future bypass tip [CHAR LIMIT=NONE] -->
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index eb17fbf..68e4e78 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -351,6 +351,10 @@
android:summary="@string/bluetooth_disable_leaudio_summary" />
<SwitchPreference
+ android:key="bluetooth_show_leaudio_device_details"
+ android:title="@string/bluetooth_show_leaudio_device_details"/>
+
+ <SwitchPreference
android:key="bluetooth_enable_leaudio_allow_list"
android:title="@string/bluetooth_enable_leaudio_allow_list"
android:summary="@string/bluetooth_enable_leaudio_allow_list_summary" />
diff --git a/res/xml/flash_notifications_settings.xml b/res/xml/flash_notifications_settings.xml
index 63937b1..85cc2cb 100644
--- a/res/xml/flash_notifications_settings.xml
+++ b/res/xml/flash_notifications_settings.xml
@@ -27,7 +27,8 @@
<com.android.settingslib.widget.IllustrationPreference
android:key="flash_notifications_illustration"
settings:searchable="false"
- settings:lottie_rawRes="@drawable/flash_notifications_illustration" />
+ settings:lottie_rawRes="@drawable/flash_notifications_illustration"
+ settings:controller="com.android.settings.accessibility.FlashNotificationIllustrationPreferenceController"/>
<SwitchPreference
android:key="camera_flash_notification_preference"
diff --git a/src/com/android/settings/SettingsApplication.java b/src/com/android/settings/SettingsApplication.java
index 49cb85e..7d8055d 100644
--- a/src/com/android/settings/SettingsApplication.java
+++ b/src/com/android/settings/SettingsApplication.java
@@ -22,9 +22,8 @@
import android.provider.Settings;
import android.util.FeatureFlagUtils;
-import androidx.window.embedding.SplitController;
-
import com.android.settings.activityembedding.ActivityEmbeddingRulesController;
+import com.android.settings.activityembedding.ActivityEmbeddingUtils;
import com.android.settings.core.instrumentation.ElapsedTimeUtils;
import com.android.settings.homepage.SettingsHomepageActivity;
import com.android.settings.spa.SettingsSpaEnvironment;
@@ -53,7 +52,7 @@
setSpaEnvironment();
if (FeatureFlagUtils.isEnabled(this, FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)
- && SplitController.getInstance(this).isSplitSupported()) {
+ && ActivityEmbeddingUtils.isSettingsSplitEnabled(this)) {
if (WizardManagerHelper.isUserSetupComplete(this)) {
new ActivityEmbeddingRulesController(this).initRules();
} else {
diff --git a/src/com/android/settings/SettingsInitialize.java b/src/com/android/settings/SettingsInitialize.java
index 1d23523..37a564b 100644
--- a/src/com/android/settings/SettingsInitialize.java
+++ b/src/com/android/settings/SettingsInitialize.java
@@ -37,9 +37,9 @@
import android.util.Log;
import androidx.annotation.VisibleForTesting;
-import androidx.window.embedding.SplitController;
import com.android.settings.Settings.CreateShortcutActivity;
+import com.android.settings.activityembedding.ActivityEmbeddingUtils;
import com.android.settings.homepage.DeepLinkHomepageActivity;
import com.android.settings.search.SearchStateReceiver;
import com.android.settingslib.utils.ThreadUtils;
@@ -166,7 +166,7 @@
DeepLinkHomepageActivity.class);
final ComponentName searchStateReceiver = new ComponentName(context,
SearchStateReceiver.class);
- final int enableState = SplitController.getInstance(context).isSplitSupported()
+ final int enableState = ActivityEmbeddingUtils.isSettingsSplitEnabled(context)
? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
pm.setComponentEnabledSetting(deepLinkHome, enableState, PackageManager.DONT_KILL_APP);
diff --git a/src/com/android/settings/accessibility/FlashNotificationIllustrationPreferenceController.java b/src/com/android/settings/accessibility/FlashNotificationIllustrationPreferenceController.java
new file mode 100644
index 0000000..9332f45
--- /dev/null
+++ b/src/com/android/settings/accessibility/FlashNotificationIllustrationPreferenceController.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.accessibility;
+
+import android.content.Context;
+import android.os.SystemProperties;
+import android.util.ArraySet;
+
+import com.android.settings.core.BasePreferenceController;
+
+import java.util.Collections;
+import java.util.Set;
+
+/** Preference controller for illustration in flash notifications page. */
+public class FlashNotificationIllustrationPreferenceController extends BasePreferenceController {
+
+ public FlashNotificationIllustrationPreferenceController(Context context,
+ String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ // TODO(b/280748155): Update tablet illustration when it's available. Hide it for now.
+ String characteristics = SystemProperties.get("ro.build.characteristics");
+ String[] characteristicsSplit = characteristics.split(",");
+ Set<String> productCharacteristics = new ArraySet<>(characteristicsSplit.length);
+ Collections.addAll(productCharacteristics, characteristicsSplit);
+ final boolean isTablet = productCharacteristics.contains("tablet");
+ return isTablet ? UNSUPPORTED_ON_DEVICE : AVAILABLE;
+ }
+}
diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
index a0dac5a..ae890f8 100644
--- a/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
+++ b/src/com/android/settings/activityembedding/ActivityEmbeddingUtils.java
@@ -18,6 +18,7 @@
import android.app.Activity;
import android.content.Context;
+import android.os.SystemProperties;
import android.util.DisplayMetrics;
import android.util.FeatureFlagUtils;
import android.util.Log;
@@ -39,6 +40,21 @@
private static final int MIN_SMALLEST_SCREEN_SPLIT_WIDTH_DP = 600;
// The minimum width of the activity to show the regular homepage layout.
private static final float MIN_REGULAR_HOMEPAGE_LAYOUT_WIDTH_DP = 380f;
+
+ /**
+ * Indicates whether to enable large screen optimization if the device supports
+ * the Activity Embedding split feature.
+ * <p>
+ * Note that the large screen optimization won't be enabled if the device doesn't support the
+ * Activity Embedding feature regardless of this property value.
+ *
+ * @see androidx.window.embedding.SplitController#getSplitSupportStatus
+ * @see androidx.window.embedding.SplitController.SplitSupportStatus#SPLIT_AVAILABLE
+ * @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);
+
private static final String TAG = "ActivityEmbeddingUtils";
/** Get the smallest width dp of the window when the split should be used. */
@@ -62,18 +78,35 @@
return context.getResources().getFloat(R.dimen.config_activity_embed_split_ratio);
}
- /** Whether to support embedding activity feature. */
+ /**
+ * Returns {@code true} to indicate that Settings app support the Activity Embedding feature on
+ * this device. Returns {@code false}, otherwise.
+ */
+ public static boolean isSettingsSplitEnabled(Context context) {
+ return SHOULD_ENABLE_LARGE_SCREEN_OPTIMIZATION
+ && SplitController.getInstance(context).getSplitSupportStatus()
+ == SplitController.SplitSupportStatus.SPLIT_AVAILABLE;
+ }
+
+ /**
+ * Checks whether to support embedding activity feature with following conditions:
+ * <ul>
+ * <li>Whether {@link #isSettingsSplitEnabled(Context)}</li>
+ * <li>Whether {@link FeatureFlagUtils#SETTINGS_SUPPORT_LARGE_SCREEN} is enabled</li>
+ * <li>Whether User setup is completed</li>
+ * </ul>
+ */
public static boolean isEmbeddingActivityEnabled(Context context) {
boolean isFlagEnabled = FeatureFlagUtils.isEnabled(context,
FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN);
- boolean isSplitSupported = SplitController.getInstance(context).isSplitSupported();
+ boolean isSettingsSplitSupported = isSettingsSplitEnabled(context);
boolean isUserSetupComplete = WizardManagerHelper.isUserSetupComplete(context);
Log.d(TAG, "isFlagEnabled = " + isFlagEnabled);
- Log.d(TAG, "isSplitSupported = " + isSplitSupported);
+ Log.d(TAG, "isSettingsSplitSupported = " + isSettingsSplitSupported);
Log.d(TAG, "isUserSetupComplete = " + isUserSetupComplete);
- return isFlagEnabled && isSplitSupported && isUserSetupComplete;
+ return isFlagEnabled && isSettingsSplitSupported && isUserSetupComplete;
}
/** Whether to show the regular or simplified homepage layout. */
diff --git a/src/com/android/settings/applications/credentials/CombinedProviderInfo.java b/src/com/android/settings/applications/credentials/CombinedProviderInfo.java
index af06a01..89a13ef 100644
--- a/src/com/android/settings/applications/credentials/CombinedProviderInfo.java
+++ b/src/com/android/settings/applications/credentials/CombinedProviderInfo.java
@@ -43,18 +43,22 @@
private final List<CredentialProviderInfo> mCredentialProviderInfos;
private final @Nullable AutofillServiceInfo mAutofillServiceInfo;
private final boolean mIsDefaultAutofillProvider;
- private final boolean mIsDefaultCredmanProvider;
+ private final boolean mIsPrimaryCredmanProvider;
/** Constructs an information instance from both autofill and credential provider. */
public CombinedProviderInfo(
@Nullable List<CredentialProviderInfo> cpis,
@Nullable AutofillServiceInfo asi,
boolean isDefaultAutofillProvider,
- boolean isDefaultCredmanProvider) {
- mCredentialProviderInfos = new ArrayList<>(cpis);
+ boolean IsPrimaryCredmanProvider) {
+ if (cpis == null) {
+ mCredentialProviderInfos = new ArrayList<>();
+ } else {
+ mCredentialProviderInfos = new ArrayList<>(cpis);
+ }
mAutofillServiceInfo = asi;
mIsDefaultAutofillProvider = isDefaultAutofillProvider;
- mIsDefaultCredmanProvider = isDefaultCredmanProvider;
+ mIsPrimaryCredmanProvider = IsPrimaryCredmanProvider;
}
/** Returns the credential provider info. */
@@ -149,8 +153,8 @@
}
/** Returns whether the provider is the default credman provider. */
- public boolean isDefaultCredmanProvider() {
- return mIsDefaultCredmanProvider;
+ public boolean isPrimaryCredmanProvider() {
+ return mIsPrimaryCredmanProvider;
}
/** Returns the settings subtitle. */
@@ -192,7 +196,13 @@
}
}
- // TODO(280454916): Add logic here.
+ // If there is a primary cred man provider then return that.
+ for (CombinedProviderInfo cpi : providers) {
+ if (cpi.isPrimaryCredmanProvider()) {
+ return cpi;
+ }
+ }
+
return null;
}
@@ -250,14 +260,14 @@
}
// Check if we have any enabled cred man services.
- boolean isDefaultCredmanProvider = false;
- if (!cpi.isEmpty()) {
- isDefaultCredmanProvider = cpi.get(0).isEnabled();
+ boolean isPrimaryCredmanProvider = false;
+ if (cpi != null && !cpi.isEmpty()) {
+ isPrimaryCredmanProvider = cpi.get(0).isPrimary();
}
cmpi.add(
new CombinedProviderInfo(
- cpi, selectedAsi, isDefaultAutofillProvider, isDefaultCredmanProvider));
+ cpi, selectedAsi, isDefaultAutofillProvider, isPrimaryCredmanProvider));
}
return cmpi;
diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
index 069336e..9d86c58a 100644
--- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java
@@ -102,6 +102,7 @@
private final Map<String, SwitchPreference> mPrefs = new HashMap<>(); // key is package name
private final List<ServiceInfo> mPendingServiceInfos = new ArrayList<>();
private final Handler mHandler = new Handler();
+ private final SettingContentObserver mSettingsContentObserver;
private @Nullable FragmentManager mFragmentManager = null;
private @Nullable Delegate mDelegate = null;
@@ -119,7 +120,9 @@
mExecutor = ContextCompat.getMainExecutor(mContext);
mCredentialManager =
getCredentialManager(context, preferenceKey.equals("credentials_test"));
- new SettingContentObserver(mHandler).register(context.getContentResolver());
+ mSettingsContentObserver = new SettingContentObserver(mHandler);
+ mSettingsContentObserver.register(context.getContentResolver());
+ mSettingsPackageMonitor.register(context, context.getMainLooper(), false);
}
private @Nullable CredentialManager getCredentialManager(Context context, boolean isTest) {
@@ -282,7 +285,7 @@
setAvailableServices(
mCredentialManager.getCredentialProviderServices(
- getUser(), CredentialManager.PROVIDER_FILTER_ALL_PROVIDERS),
+ getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY),
null);
}
@@ -321,7 +324,7 @@
mEnabledPackageNames.clear();
for (CredentialProviderInfo cpi : availableServices) {
- if (cpi.isEnabled()) {
+ if (cpi.isEnabled() && !cpi.isPrimary()) {
mEnabledPackageNames.add(cpi.getServiceInfo().packageName);
}
}
@@ -560,8 +563,20 @@
return;
}
+ // Get the existing primary providers since we don't touch them in
+ // this part of the UI we should just copy them over.
+ Set<String> primaryServices = new HashSet<>();
List<String> enabledServices = getEnabledSettings();
+ for (CredentialProviderInfo service : mServices) {
+ if (service.isPrimary()) {
+ String flattened = service.getServiceInfo().getComponentName().flattenToString();
+ primaryServices.add(flattened);
+ enabledServices.add(flattened);
+ }
+ }
+
mCredentialManager.setEnabledProviders(
+ new ArrayList<>(primaryServices),
enabledServices,
getUser(),
mExecutor,
@@ -569,6 +584,7 @@
@Override
public void onResult(Void result) {
Log.i(TAG, "setEnabledProviders success");
+ updateFromExternal();
}
@Override
diff --git a/src/com/android/settings/applications/credentials/DefaultCombinedPicker.java b/src/com/android/settings/applications/credentials/DefaultCombinedPicker.java
index cfaf7a2..634be4c 100644
--- a/src/com/android/settings/applications/credentials/DefaultCombinedPicker.java
+++ b/src/com/android/settings/applications/credentials/DefaultCombinedPicker.java
@@ -47,7 +47,9 @@
import com.android.settingslib.widget.CandidateInfo;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
public class DefaultCombinedPicker extends DefaultAppPickerFragment {
@@ -338,9 +340,9 @@
return true;
}
- private void setProviders(String autofillProvider, List<String> credManProviders) {
+ private void setProviders(String autofillProvider, List<String> primaryCredManProviders) {
if (TextUtils.isEmpty(autofillProvider)) {
- if (credManProviders.size() > 0) {
+ if (primaryCredManProviders.size() > 0) {
autofillProvider =
CredentialManagerPreferenceController
.AUTOFILL_CREDMAN_ONLY_PROVIDER_PLACEHOLDER;
@@ -350,12 +352,27 @@
Settings.Secure.putStringForUser(
getContext().getContentResolver(), AUTOFILL_SETTING, autofillProvider, mUserId);
- CredentialManager service = getCredentialProviderService();
+ final CredentialManager service = getCredentialProviderService();
if (service == null) {
return;
}
+ // Get the existing secondary providers since we don't touch them in
+ // this part of the UI we should just copy them over.
+ final List<String> credManProviders = new ArrayList<>();
+ for (CredentialProviderInfo cpi :
+ service.getCredentialProviderServices(
+ mUserId, CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY)) {
+
+ if (cpi.isEnabled()) {
+ credManProviders.add(cpi.getServiceInfo().getComponentName().flattenToString());
+ }
+ }
+
+ credManProviders.addAll(primaryCredManProviders);
+
service.setEnabledProviders(
+ primaryCredManProviders,
credManProviders,
mUserId,
ContextCompat.getMainExecutor(getContext()),
diff --git a/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java b/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java
index ca049bc..64d4f0d 100644
--- a/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java
+++ b/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java
@@ -135,12 +135,12 @@
/** Provides Intent to setting activity for the specified autofill service. */
static final class AutofillSettingIntentProvider {
- private final String mSelectedKey;
+ private final String mKey;
private final Context mContext;
private final int mUserId;
public AutofillSettingIntentProvider(Context context, int userId, String key) {
- mSelectedKey = key;
+ mKey = key;
mContext = context;
mUserId = userId;
}
@@ -153,10 +153,9 @@
for (ResolveInfo resolveInfo : resolveInfos) {
final ServiceInfo serviceInfo = resolveInfo.serviceInfo;
- final String flattenKey =
- new ComponentName(serviceInfo.packageName, serviceInfo.name)
- .flattenToString();
- if (TextUtils.equals(mSelectedKey, flattenKey)) {
+
+ // If there are multiple autofill services then pick the first one.
+ if (mKey.startsWith(serviceInfo.packageName)) {
final String settingsActivity;
try {
settingsActivity =
@@ -164,7 +163,7 @@
.getSettingsActivity();
} catch (SecurityException e) {
// Service does not declare the proper permission, ignore it.
- Log.w(TAG, "Error getting info for " + serviceInfo + ": " + e);
+ Log.e(TAG, "Error getting info for " + serviceInfo + ": " + e);
return null;
}
if (TextUtils.isEmpty(settingsActivity)) {
diff --git a/src/com/android/settings/biometrics/activeunlock/ActiveUnlockStatusUtils.java b/src/com/android/settings/biometrics/activeunlock/ActiveUnlockStatusUtils.java
index 4ff2b87..8f9da54 100644
--- a/src/com/android/settings/biometrics/activeunlock/ActiveUnlockStatusUtils.java
+++ b/src/com/android/settings/biometrics/activeunlock/ActiveUnlockStatusUtils.java
@@ -268,6 +268,30 @@
}
}
+ /**
+ * Returns the preference title of how to use biometrics when active unlock is enabled.
+ */
+ public String getUseBiometricTitleForActiveUnlock() {
+ final boolean faceAllowed = Utils.hasFaceHardware(mContext);
+ final boolean fingerprintAllowed = Utils.hasFingerprintHardware(mContext);
+
+ return mContext.getString(getUseBiometricTitleRes(faceAllowed, fingerprintAllowed));
+ }
+
+ @StringRes
+ private static int getUseBiometricTitleRes(
+ boolean isFaceAllowed, boolean isFingerprintAllowed) {
+ if (isFaceAllowed && isFingerprintAllowed) {
+ return R.string.biometric_settings_use_face_fingerprint_or_watch_for;
+ } else if (isFaceAllowed) {
+ return R.string.biometric_settings_use_face_or_watch_for;
+ } else if (isFingerprintAllowed) {
+ return R.string.biometric_settings_use_fingerprint_or_watch_for;
+ } else {
+ return R.string.biometric_settings_use_watch_for;
+ }
+ }
+
private static String getFlagState() {
return DeviceConfig.getProperty(DeviceConfig.NAMESPACE_REMOTE_AUTH, CONFIG_FLAG_NAME);
}
diff --git a/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java b/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java
index d0e986f..671a5b6 100644
--- a/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java
+++ b/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java
@@ -46,6 +46,7 @@
private static final String KEY_UNLOCK_PHONE = "biometric_settings_biometric_keyguard";
private static final String KEY_USE_IN_APPS = "biometric_settings_biometric_app";
private static final String KEY_INTRO_PREFERENCE = "biometric_intro";
+ private static final String KEY_USE_BIOMETRIC_PREFERENCE = "biometric_ways_to_use";
private ActiveUnlockStatusUtils mActiveUnlockStatusUtils;
private CombinedBiometricStatusUtils mCombinedBiometricStatusUtils;
@@ -83,6 +84,11 @@
if (introPreference != null) {
introPreference.setTitle(mActiveUnlockStatusUtils.getIntroForActiveUnlock());
}
+ final Preference useBiometricPreference = findPreference(KEY_USE_BIOMETRIC_PREFERENCE);
+ if (useBiometricPreference != null) {
+ useBiometricPreference.setTitle(
+ mActiveUnlockStatusUtils.getUseBiometricTitleForActiveUnlock());
+ }
getActivity().setTitle(mActiveUnlockStatusUtils.getTitleForActiveUnlock());
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index f69cf58..208fba7 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -77,6 +77,7 @@
private Map<String, List<CachedBluetoothDevice>> mProfileDeviceMap =
new HashMap<String, List<CachedBluetoothDevice>>();
private boolean mIsLeContactSharingEnabled = false;
+ private boolean mIsLeAudioToggleEnabled = false;
@VisibleForTesting
PreferenceCategory mProfilesContainer;
@@ -97,6 +98,8 @@
mProfilesContainer.setLayoutResource(R.layout.preference_bluetooth_profile_category);
mIsLeContactSharingEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
SettingsUIDeviceConfig.BT_LE_AUDIO_CONTACT_SHARING_ENABLED, true);
+ mIsLeAudioToggleEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
+ SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
// Call refresh here even though it will get called later in onResume, to avoid the
// list of switches appearing to "pop" into the page.
refresh();
@@ -142,6 +145,10 @@
profilePref.setEnabled(!mCachedDevice.isBusy());
}
+ if (profile instanceof LeAudioProfile && !mIsLeAudioToggleEnabled) {
+ profilePref.setVisible(false);
+ }
+
if (profile instanceof MapProfile) {
profilePref.setChecked(device.getMessageAccessPermission()
== BluetoothDevice.ACCESS_ALLOWED);
diff --git a/src/com/android/settings/bluetooth/RequestPermissionActivity.java b/src/com/android/settings/bluetooth/RequestPermissionActivity.java
index 620cfb0..32ca277 100644
--- a/src/com/android/settings/bluetooth/RequestPermissionActivity.java
+++ b/src/com/android/settings/bluetooth/RequestPermissionActivity.java
@@ -72,6 +72,7 @@
private int mRequest;
private AlertDialog mDialog;
+ private AlertDialog mRequestDialog;
private BroadcastReceiver mReceiver;
@@ -96,33 +97,35 @@
if (mRequest == REQUEST_DISABLE) {
switch (btState) {
case BluetoothAdapter.STATE_OFF:
- case BluetoothAdapter.STATE_TURNING_OFF: {
+ case BluetoothAdapter.STATE_TURNING_OFF:
proceedAndFinish();
- } break;
-
+ break;
case BluetoothAdapter.STATE_ON:
- case BluetoothAdapter.STATE_TURNING_ON: {
- RequestPermissionHelper.INSTANCE.requestDisable(this, mAppLabel,
- () -> {
- onDisableConfirmed();
- return Unit.INSTANCE;
- },
- () -> {
- cancelAndFinish();
- return Unit.INSTANCE;
- });
- } break;
-
- default: {
+ case BluetoothAdapter.STATE_TURNING_ON:
+ mRequestDialog =
+ RequestPermissionHelper.INSTANCE.requestDisable(this, mAppLabel,
+ () -> {
+ onDisableConfirmed();
+ return Unit.INSTANCE;
+ },
+ () -> {
+ cancelAndFinish();
+ return Unit.INSTANCE;
+ });
+ if (mRequestDialog != null) {
+ mRequestDialog.show();
+ }
+ break;
+ default:
Log.e(TAG, "Unknown adapter state: " + btState);
cancelAndFinish();
- } break;
+ break;
}
} else {
switch (btState) {
case BluetoothAdapter.STATE_OFF:
case BluetoothAdapter.STATE_TURNING_OFF:
- case BluetoothAdapter.STATE_TURNING_ON: {
+ case BluetoothAdapter.STATE_TURNING_ON:
/*
* Strictly speaking STATE_TURNING_ON belong with STATE_ON;
* however, BT may not be ready when the user clicks yes and we
@@ -131,20 +134,23 @@
* case via the broadcast receiver.
*/
- // Start the helper activity to ask the user about enabling bt AND discovery
- RequestPermissionHelper.INSTANCE.requestEnable(this, mAppLabel,
- mRequest == REQUEST_ENABLE_DISCOVERABLE ? mTimeout : -1,
- () -> {
- onEnableConfirmed();
- return Unit.INSTANCE;
- },
- () -> {
- cancelAndFinish();
- return Unit.INSTANCE;
- });
- } break;
-
- case BluetoothAdapter.STATE_ON: {
+ // Show the helper dialog to ask the user about enabling bt AND discovery
+ mRequestDialog =
+ RequestPermissionHelper.INSTANCE.requestEnable(this, mAppLabel,
+ mRequest == REQUEST_ENABLE_DISCOVERABLE ? mTimeout : -1,
+ () -> {
+ onEnableConfirmed();
+ return Unit.INSTANCE;
+ },
+ () -> {
+ cancelAndFinish();
+ return Unit.INSTANCE;
+ });
+ if (mRequestDialog != null) {
+ mRequestDialog.show();
+ }
+ break;
+ case BluetoothAdapter.STATE_ON:
if (mRequest == REQUEST_ENABLE) {
// Nothing to do. Already enabled.
proceedAndFinish();
@@ -152,12 +158,11 @@
// Ask the user about enabling discovery mode
createDialog();
}
- } break;
-
- default: {
+ break;
+ default:
Log.e(TAG, "Unknown adapter state: " + btState);
cancelAndFinish();
- } break;
+ break;
}
}
}
@@ -275,10 +280,6 @@
}
}
- if (mDialog != null) {
- mDialog.dismiss();
- }
-
setResult(returnCode);
finish();
}
@@ -365,6 +366,14 @@
unregisterReceiver(mReceiver);
mReceiver = null;
}
+ if (mDialog != null && mDialog.isShowing()) {
+ mDialog.dismiss();
+ mDialog = null;
+ }
+ if (mRequestDialog != null && mRequestDialog.isShowing()) {
+ mRequestDialog.dismiss();
+ mRequestDialog = null;
+ }
}
@Override
diff --git a/src/com/android/settings/bluetooth/RequestPermissionHelper.kt b/src/com/android/settings/bluetooth/RequestPermissionHelper.kt
index 000a7d1..73084e4 100644
--- a/src/com/android/settings/bluetooth/RequestPermissionHelper.kt
+++ b/src/com/android/settings/bluetooth/RequestPermissionHelper.kt
@@ -30,20 +30,20 @@
timeout: Int,
onAllow: () -> Unit,
onDeny: () -> Unit,
- ) {
+ ): AlertDialog? {
if (context.resources.getBoolean(R.bool.auto_confirm_bluetooth_activation_dialog)) {
// Don't even show the dialog if configured this way
onAllow()
- return
+ return null
}
- AlertDialog.Builder(context).apply {
+ return AlertDialog.Builder(context).apply {
setMessage(context.getEnableMessage(timeout, appLabel))
setPositiveButton(R.string.allow) { _, _ ->
if (context.isDisallowBluetooth()) onDeny() else onAllow()
}
setNegativeButton(R.string.deny) { _, _ -> onDeny() }
setOnCancelListener { onDeny() }
- }.show()
+ }.create()
}
fun requestDisable(
@@ -51,18 +51,18 @@
appLabel: CharSequence?,
onAllow: () -> Unit,
onDeny: () -> Unit,
- ) {
+ ): AlertDialog? {
if (context.resources.getBoolean(R.bool.auto_confirm_bluetooth_activation_dialog)) {
// Don't even show the dialog if configured this way
onAllow()
- return
+ return null
}
- AlertDialog.Builder(context).apply {
+ return AlertDialog.Builder(context).apply {
setMessage(context.getDisableMessage(appLabel))
setPositiveButton(R.string.allow) { _, _ -> onAllow() }
setNegativeButton(R.string.deny) { _, _ -> onDeny() }
setOnCancelListener { onDeny() }
- }.show()
+ }.create()
}
}
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java b/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
index 947c5ac..1187c59 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusDeviceUpdater.java
@@ -165,8 +165,7 @@
}
mUsiPreference.setKey(PREF_KEY);
mUsiPreference.setTitle(R.string.stylus_connected_devices_title);
- // TODO(b/250909304): pending actual icon visD
- mUsiPreference.setIcon(R.drawable.ic_edit);
+ mUsiPreference.setIcon(R.drawable.ic_stylus);
mUsiPreference.setOnPreferenceClickListener((Preference p) -> {
mMetricsFeatureProvider.logClickedPreference(p, mFragment.getMetricsCategory());
launchDeviceDetails();
diff --git a/src/com/android/settings/connecteddevice/stylus/StylusUsiHeaderController.java b/src/com/android/settings/connecteddevice/stylus/StylusUsiHeaderController.java
index 379815b..23db3cb 100644
--- a/src/com/android/settings/connecteddevice/stylus/StylusUsiHeaderController.java
+++ b/src/com/android/settings/connecteddevice/stylus/StylusUsiHeaderController.java
@@ -70,8 +70,7 @@
ImageView iconView = mHeaderPreference.findViewById(R.id.entity_header_icon);
if (iconView != null) {
- // TODO(b/250909304): get proper icon once VisD ready
- iconView.setImageResource(R.drawable.ic_edit);
+ iconView.setImageResource(R.drawable.ic_stylus);
iconView.setContentDescription("Icon for stylus");
}
refresh();
diff --git a/src/com/android/settings/core/SettingsUIDeviceConfig.java b/src/com/android/settings/core/SettingsUIDeviceConfig.java
index 94074df..404b0b4 100644
--- a/src/com/android/settings/core/SettingsUIDeviceConfig.java
+++ b/src/com/android/settings/core/SettingsUIDeviceConfig.java
@@ -42,4 +42,9 @@
* {@code true} whether or not event_log for generic actions is enabled. Default is true.
*/
public static final String GENERIC_EVENT_LOGGING_ENABLED = "event_logging_enabled";
+ /**
+ * {@code true} whether to show LE Audio toggle in device detail page. Default is false.
+ */
+ public static final String BT_LE_AUDIO_DEVICE_DETAIL_ENABLED =
+ "bt_le_audio_device_detail_enabled";
}
diff --git a/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java b/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
new file mode 100644
index 0000000..0945f0d
--- /dev/null
+++ b/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceController.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothStatusCodes;
+import android.content.Context;
+import android.provider.DeviceConfig;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.core.SettingsUIDeviceConfig;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+/**
+ * Preference controller to control whether display Bluetooth LE audio toggle in device detail
+ * settings page or not.
+ */
+public class BluetoothLeAudioDeviceDetailsPreferenceController
+ extends DeveloperOptionsPreferenceController
+ implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+ private static final String PREFERENCE_KEY = "bluetooth_show_leaudio_device_details";
+ static int sLeAudioSupportedStateCache = BluetoothStatusCodes.ERROR_UNKNOWN;
+
+ @VisibleForTesting
+ BluetoothAdapter mBluetoothAdapter;
+
+ public BluetoothLeAudioDeviceDetailsPreferenceController(Context context) {
+ super(context);
+ mBluetoothAdapter = context.getSystemService(BluetoothManager.class).getAdapter();
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return PREFERENCE_KEY;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ if (sLeAudioSupportedStateCache == BluetoothStatusCodes.ERROR_UNKNOWN
+ && mBluetoothAdapter != null) {
+ int isLeAudioSupported = mBluetoothAdapter.isLeAudioSupported();
+ if (isLeAudioSupported != BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED) {
+ sLeAudioSupportedStateCache = isLeAudioSupported;
+ }
+ }
+
+ // Display the option only if LE Audio is supported
+ return (sLeAudioSupportedStateCache == BluetoothStatusCodes.FEATURE_SUPPORTED);
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ final boolean isEnabled = (Boolean) newValue;
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_SETTINGS_UI,
+ SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED,
+ isEnabled ? "true" : "false", false);
+ return true;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ if (!isAvailable()) {
+ return;
+ }
+
+ final boolean leAudioDeviceDetailEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SETTINGS_UI,
+ SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
+
+ ((SwitchPreference) mPreference).setChecked(leAudioDeviceDetailEnabled);
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchDisabled() {
+ super.onDeveloperOptionsSwitchDisabled();
+ // Reset the toggle to null when the developer option is disabled
+ DeviceConfig.setProperty(
+ DeviceConfig.NAMESPACE_SETTINGS_UI,
+ SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "null", false);
+ }
+}
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index f8ce975..87d8c17 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -660,6 +660,7 @@
controllers.add(new BluetoothAvrcpVersionPreferenceController(context));
controllers.add(new BluetoothMapVersionPreferenceController(context));
controllers.add(new BluetoothLeAudioPreferenceController(context, fragment));
+ controllers.add(new BluetoothLeAudioDeviceDetailsPreferenceController(context));
controllers.add(new BluetoothLeAudioAllowListPreferenceController(context, fragment));
controllers.add(new BluetoothA2dpHwOffloadPreferenceController(context, fragment));
controllers.add(new BluetoothLeAudioHwOffloadPreferenceController(context, fragment));
diff --git a/src/com/android/settings/dream/DreamAdapter.java b/src/com/android/settings/dream/DreamAdapter.java
index aa71aab..1d1c3bd 100644
--- a/src/com/android/settings/dream/DreamAdapter.java
+++ b/src/com/android/settings/dream/DreamAdapter.java
@@ -19,7 +19,6 @@
import android.annotation.LayoutRes;
import android.content.Context;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.VectorDrawable;
import android.text.TextUtils;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
@@ -86,10 +85,6 @@
final Drawable icon = item.isActive()
? mContext.getDrawable(R.drawable.ic_dream_check_circle)
: item.getIcon().mutate();
- if (icon instanceof VectorDrawable) {
- icon.setTintList(
- mContext.getColorStateList(R.color.dream_card_icon_color_state_list));
- }
final int iconSize = mContext.getResources().getDimensionPixelSize(
R.dimen.dream_item_icon_size);
icon.setBounds(0, 0, iconSize, iconSize);
diff --git a/src/com/android/settings/homepage/SettingsHomepageActivity.java b/src/com/android/settings/homepage/SettingsHomepageActivity.java
index 7713e27..03bc1b3 100644
--- a/src/com/android/settings/homepage/SettingsHomepageActivity.java
+++ b/src/com/android/settings/homepage/SettingsHomepageActivity.java
@@ -58,7 +58,6 @@
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.window.embedding.ActivityEmbeddingController;
-import androidx.window.embedding.SplitController;
import androidx.window.embedding.SplitRule;
import com.android.settings.R;
@@ -429,7 +428,7 @@
private boolean shouldLaunchDeepLinkIntentToRight() {
if (!FeatureFlagUtils.isEnabled(this, FeatureFlagUtils.SETTINGS_SUPPORT_LARGE_SCREEN)
- || !SplitController.getInstance(this).isSplitSupported()) {
+ || !ActivityEmbeddingUtils.isSettingsSplitEnabled(this)) {
return false;
}
diff --git a/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceController.java b/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceController.java
index 0bbfb98..10d3013 100644
--- a/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceController.java
+++ b/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceController.java
@@ -30,12 +30,12 @@
@Override
public boolean isChecked() {
- return InputSettings.useTouchpadNaturalScrolling(mContext);
+ return !InputSettings.useTouchpadNaturalScrolling(mContext);
}
@Override
public boolean setChecked(boolean isChecked) {
- InputSettings.setTouchpadNaturalScrolling(mContext, isChecked);
+ InputSettings.setTouchpadNaturalScrolling(mContext, !isChecked);
return true;
}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
index 02455a1..38f6596 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
@@ -940,28 +940,11 @@
* Copied from WifiCallingPreferenceController#isWifiCallingEnabled()
*/
public static boolean isWifiCallingEnabled(Context context, int subId,
- @Nullable WifiCallingQueryImsState queryImsState,
- @Nullable PhoneAccountHandle phoneAccountHandle) {
- if (phoneAccountHandle == null){
- phoneAccountHandle = context.getSystemService(TelecomManager.class)
- .getSimCallManagerForSubscription(subId);
+ @Nullable WifiCallingQueryImsState queryImsState) {
+ if (queryImsState == null) {
+ queryImsState = new WifiCallingQueryImsState(context, subId);
}
- boolean isWifiCallingEnabled;
- if (phoneAccountHandle != null) {
- final Intent intent = buildPhoneAccountConfigureIntent(context, phoneAccountHandle);
- if (intent == null) {
- Log.d(TAG, "Can not get phoneAccount configure intent.");
- isWifiCallingEnabled = false;
- } else {
- isWifiCallingEnabled = true;
- }
- } else {
- if (queryImsState == null) {
- queryImsState = new WifiCallingQueryImsState(context, subId);
- }
- isWifiCallingEnabled = queryImsState.isReadyToWifiCalling();
- }
- return isWifiCallingEnabled;
+ return queryImsState.isReadyToWifiCalling();
}
/**
diff --git a/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java b/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java
index 7ad9e03..ebfb283 100644
--- a/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java
+++ b/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java
@@ -22,7 +22,6 @@
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.PersistableBundle;
import android.provider.Settings;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
@@ -314,8 +313,7 @@
@VisibleForTesting
protected boolean shouldShowWifiCallingForSub(int subId) {
if (SubscriptionManager.isValidSubscriptionId(subId)
- && MobileNetworkUtils.isWifiCallingEnabled(mContext, subId, queryImsState(subId),
- null)) {
+ && MobileNetworkUtils.isWifiCallingEnabled(mContext, subId, queryImsState(subId))) {
return true;
}
return false;
diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java
index 1bc2f90..03cc23f 100644
--- a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java
+++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java
@@ -71,7 +71,7 @@
@Override
public int getAvailabilityStatus(int subId) {
return SubscriptionManager.isValidSubscriptionId(subId)
- && MobileNetworkUtils.isWifiCallingEnabled(mContext, subId, null, null)
+ && MobileNetworkUtils.isWifiCallingEnabled(mContext, subId, null)
? AVAILABLE
: UNSUPPORTED_ON_DEVICE;
}
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index e35b0d8..0bf13b1 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -854,6 +854,19 @@
}
@Override
+ public void onStop() {
+ super.onStop();
+ // hasCredential checks to see if user chooses a password for screen lock. If the
+ // screen lock is None or Swipe, we do not want to call getActivity().finish().
+ // Otherwise, bugs would be caused. (e.g. b/278488549, b/278530059)
+ final boolean hasCredential = mLockPatternUtils.isSecure(mUserId);
+ if (!getActivity().isChangingConfigurations()
+ && !mWaitingForConfirmation && hasCredential) {
+ getActivity().finish();
+ }
+ }
+
+ @Override
public void onDestroy() {
super.onDestroy();
if (mUserPassword != null) {
diff --git a/src/com/android/settings/spa/SpaActivity.kt b/src/com/android/settings/spa/SpaActivity.kt
index 27f7241..2b52b21 100644
--- a/src/com/android/settings/spa/SpaActivity.kt
+++ b/src/com/android/settings/spa/SpaActivity.kt
@@ -22,14 +22,34 @@
import android.os.RemoteException
import android.os.UserHandle
import android.util.Log
+import androidx.annotation.VisibleForTesting
+import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
import com.android.settingslib.spa.framework.BrowseActivity
+import com.android.settingslib.spa.framework.common.SettingsPage
import com.android.settingslib.spa.framework.util.SESSION_BROWSE
import com.android.settingslib.spa.framework.util.SESSION_EXTERNAL
import com.android.settingslib.spa.framework.util.appendSpaParams
+import com.google.android.setupcompat.util.WizardManagerHelper
class SpaActivity : BrowseActivity() {
+ override fun isPageEnabled(page: SettingsPage) =
+ super.isPageEnabled(page) && !isSuwAndPageBlocked(page.sppName)
+
companion object {
private const val TAG = "SpaActivity"
+
+ /** The pages that blocked from SUW. */
+ private val SuwBlockedPages = setOf(AppInfoSettingsProvider.name)
+
+ @VisibleForTesting
+ fun Context.isSuwAndPageBlocked(name: String): Boolean =
+ if (name in SuwBlockedPages && !WizardManagerHelper.isDeviceProvisioned(this)) {
+ Log.w(TAG, "$name blocked before SUW completed.");
+ true
+ } else {
+ false
+ }
+
@JvmStatic
fun Context.startSpaActivity(destination: String) {
val intent = Intent(this, SpaActivity::class.java)
diff --git a/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt b/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt
index 9b36335..527c6d9 100644
--- a/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt
+++ b/src/com/android/settings/spa/app/specialaccess/AlarmsAndRemindersAppList.kt
@@ -19,12 +19,14 @@
import android.Manifest
import android.app.AlarmManager
import android.app.compat.CompatChanges
+import android.app.settings.SettingsEnums
import android.content.Context
import android.content.pm.ApplicationInfo
import android.os.PowerExemptionManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.livedata.observeAsState
import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory
import com.android.settingslib.spa.framework.compose.stateOf
import com.android.settingslib.spaprivileged.model.app.AppRecord
import com.android.settingslib.spaprivileged.model.app.IPackageManagers
@@ -85,6 +87,17 @@
override fun setAllowed(record: AlarmsAndRemindersAppRecord, newAllowed: Boolean) {
record.controller.setAllowed(newAllowed)
+ logPermissionChange(newAllowed)
+ }
+
+ private fun logPermissionChange(newAllowed: Boolean) {
+ FeatureFactory.getFactory(context).metricsFeatureProvider.action(
+ SettingsEnums.PAGE_UNKNOWN,
+ SettingsEnums.ACTION_ALARMS_AND_REMINDERS_TOGGLE,
+ SettingsEnums.ALARMS_AND_REMINDERS,
+ "",
+ if (newAllowed) 1 else 0
+ )
}
private fun createRecord(
diff --git a/src/com/android/settings/spa/app/specialaccess/AllFilesAccess.kt b/src/com/android/settings/spa/app/specialaccess/AllFilesAccess.kt
index 6466e03..16520fa 100644
--- a/src/com/android/settings/spa/app/specialaccess/AllFilesAccess.kt
+++ b/src/com/android/settings/spa/app/specialaccess/AllFilesAccess.kt
@@ -18,9 +18,12 @@
import android.Manifest
import android.app.AppOpsManager
+import android.app.settings.SettingsEnums
import android.content.Context
import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory
import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
object AllFilesAccessAppListProvider : TogglePermissionAppListProvider {
@@ -35,4 +38,17 @@
override val appOp = AppOpsManager.OP_MANAGE_EXTERNAL_STORAGE
override val permission = Manifest.permission.MANAGE_EXTERNAL_STORAGE
override val setModeByUid = true
+
+ override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+ super.setAllowed(record, newAllowed)
+ logPermissionChange(newAllowed)
+ }
+
+ private fun logPermissionChange(newAllowed: Boolean) {
+ val category = when {
+ newAllowed -> SettingsEnums.APP_SPECIAL_PERMISSION_MANAGE_EXT_STRG_ALLOW
+ else -> SettingsEnums.APP_SPECIAL_PERMISSION_MANAGE_EXT_STRG_DENY
+ }
+ FeatureFactory.getFactory(context).metricsFeatureProvider.action(context, category, "")
+ }
}
diff --git a/src/com/android/settings/spa/app/specialaccess/DisplayOverOtherApps.kt b/src/com/android/settings/spa/app/specialaccess/DisplayOverOtherApps.kt
index d3cd2b5..7812675 100644
--- a/src/com/android/settings/spa/app/specialaccess/DisplayOverOtherApps.kt
+++ b/src/com/android/settings/spa/app/specialaccess/DisplayOverOtherApps.kt
@@ -18,9 +18,12 @@
import android.Manifest
import android.app.AppOpsManager
+import android.app.settings.SettingsEnums
import android.content.Context
import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory
import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
object DisplayOverOtherAppsAppListProvider : TogglePermissionAppListProvider {
@@ -34,4 +37,17 @@
override val footerResId = R.string.allow_overlay_description
override val appOp = AppOpsManager.OP_SYSTEM_ALERT_WINDOW
override val permission = Manifest.permission.SYSTEM_ALERT_WINDOW
+
+ override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+ super.setAllowed(record, newAllowed)
+ logPermissionChange(newAllowed)
+ }
+
+ private fun logPermissionChange(newAllowed: Boolean) {
+ val category = when {
+ newAllowed -> SettingsEnums.APP_SPECIAL_PERMISSION_APPDRAW_ALLOW
+ else -> SettingsEnums.APP_SPECIAL_PERMISSION_APPDRAW_DENY
+ }
+ FeatureFactory.getFactory(context).metricsFeatureProvider.action(context, category, "")
+ }
}
diff --git a/src/com/android/settings/spa/app/specialaccess/MediaManagementApps.kt b/src/com/android/settings/spa/app/specialaccess/MediaManagementApps.kt
index 6c7678a..e8935e6 100644
--- a/src/com/android/settings/spa/app/specialaccess/MediaManagementApps.kt
+++ b/src/com/android/settings/spa/app/specialaccess/MediaManagementApps.kt
@@ -18,9 +18,12 @@
import android.Manifest
import android.app.AppOpsManager
+import android.app.settings.SettingsEnums
import android.content.Context
import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory
import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
object MediaManagementAppsAppListProvider : TogglePermissionAppListProvider {
@@ -35,4 +38,19 @@
override val appOp = AppOpsManager.OP_MANAGE_MEDIA
override val permission = Manifest.permission.MANAGE_MEDIA
override val setModeByUid = true
+
+ override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+ super.setAllowed(record, newAllowed)
+ logPermissionChange(newAllowed)
+ }
+
+ private fun logPermissionChange(newAllowed: Boolean) {
+ FeatureFactory.getFactory(context).metricsFeatureProvider.action(
+ SettingsEnums.PAGE_UNKNOWN,
+ SettingsEnums.ACTION_MEDIA_MANAGEMENT_APPS_TOGGLE,
+ SettingsEnums.MEDIA_MANAGEMENT_APPS,
+ "",
+ if (newAllowed) 1 else 0
+ )
+ }
}
\ No newline at end of file
diff --git a/src/com/android/settings/spa/app/specialaccess/ModifySystemSettings.kt b/src/com/android/settings/spa/app/specialaccess/ModifySystemSettings.kt
index 9a70871..668cc8c 100644
--- a/src/com/android/settings/spa/app/specialaccess/ModifySystemSettings.kt
+++ b/src/com/android/settings/spa/app/specialaccess/ModifySystemSettings.kt
@@ -18,9 +18,12 @@
import android.Manifest
import android.app.AppOpsManager
+import android.app.settings.SettingsEnums
import android.content.Context
import com.android.settings.R
+import com.android.settings.overlay.FeatureFactory
import com.android.settingslib.spaprivileged.template.app.AppOpPermissionListModel
+import com.android.settingslib.spaprivileged.template.app.AppOpPermissionRecord
import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
object ModifySystemSettingsAppListProvider : TogglePermissionAppListProvider {
@@ -34,4 +37,17 @@
override val footerResId = R.string.write_settings_description
override val appOp = AppOpsManager.OP_WRITE_SETTINGS
override val permission = Manifest.permission.WRITE_SETTINGS
+
+ override fun setAllowed(record: AppOpPermissionRecord, newAllowed: Boolean) {
+ super.setAllowed(record, newAllowed)
+ logPermissionChange(newAllowed)
+ }
+
+ private fun logPermissionChange(newAllowed: Boolean) {
+ val category = when {
+ newAllowed -> SettingsEnums.APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_ALLOW
+ else -> SettingsEnums.APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_DENY
+ }
+ FeatureFactory.getFactory(context).metricsFeatureProvider.action(context, category, "")
+ }
}
\ No newline at end of file
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettings.java b/src/com/android/settings/wifi/calling/WifiCallingSettings.java
index 42ce1b1..0c3457c 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettings.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettings.java
@@ -257,8 +257,10 @@
for (SubscriptionInfo subInfo : subInfoList) {
int subId = subInfo.getSubscriptionId();
try {
- if (MobileNetworkUtils.isWifiCallingEnabled(getContext(), subId,
- queryImsState(subId), null)) {
+ if (MobileNetworkUtils.isWifiCallingEnabled(
+ getContext(),
+ subId,
+ queryImsState(subId))) {
selectedList.add(subInfo);
}
} catch (Exception exception) {}
diff --git a/tests/robotests/src/com/android/settings/biometrics/activeunlock/ActiveUnlockStatusUtilsTest.java b/tests/robotests/src/com/android/settings/biometrics/activeunlock/ActiveUnlockStatusUtilsTest.java
index d420f78..e5eac12 100644
--- a/tests/robotests/src/com/android/settings/biometrics/activeunlock/ActiveUnlockStatusUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/biometrics/activeunlock/ActiveUnlockStatusUtilsTest.java
@@ -222,4 +222,44 @@
.isEqualTo(mApplicationContext.getString(
R.string.biometric_settings_use_face_or_watch_preference_summary));
}
+
+ @Test
+ public void getUseBiometricTitle_faceAndFingerprintEnabled_returnsFaceFingerprintOrWatch() {
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+
+ assertThat(mActiveUnlockStatusUtils.getUseBiometricTitleForActiveUnlock())
+ .isEqualTo(mApplicationContext.getString(
+ R.string.biometric_settings_use_face_fingerprint_or_watch_for));
+ }
+
+ @Test
+ public void getUseBiometricTitle_fingerprintEnabled_returnsFingerprintOrWatch() {
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
+ when(mFaceManager.isHardwareDetected()).thenReturn(false);
+
+ assertThat(mActiveUnlockStatusUtils.getUseBiometricTitleForActiveUnlock())
+ .isEqualTo(mApplicationContext.getString(
+ R.string.biometric_settings_use_fingerprint_or_watch_for));
+ }
+
+ @Test
+ public void getUseBiometricTitle_faceEnabled_returnsFaceOrWatch() {
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+ when(mFaceManager.isHardwareDetected()).thenReturn(true);
+
+ assertThat(mActiveUnlockStatusUtils.getUseBiometricTitleForActiveUnlock())
+ .isEqualTo(mApplicationContext.getString(
+ R.string.biometric_settings_use_face_or_watch_for));
+ }
+
+ @Test
+ public void getUseBiometricTitle_withoutFaceOrFingerprint_returnsWatch() {
+ when(mFingerprintManager.isHardwareDetected()).thenReturn(false);
+ when(mFaceManager.isHardwareDetected()).thenReturn(false);
+
+ assertThat(mActiveUnlockStatusUtils.getUseBiometricTitleForActiveUnlock())
+ .isEqualTo(mApplicationContext.getString(
+ R.string.biometric_settings_use_watch_for));
+ }
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionActivityTest.kt b/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionActivityTest.kt
new file mode 100644
index 0000000..13cbb35
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionActivityTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.bluetooth
+
+import android.bluetooth.BluetoothAdapter
+import android.content.Intent
+import com.android.settings.testutils.shadow.ShadowAlertDialogCompat
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.android.controller.ActivityController
+import org.robolectric.annotation.Config
+import org.robolectric.shadow.api.Shadow
+import org.robolectric.shadows.ShadowBluetoothAdapter
+
+@RunWith(RobolectricTestRunner::class)
+@Config(shadows = [ShadowAlertDialogCompat::class, ShadowBluetoothAdapter::class])
+class RequestPermissionActivityTest {
+ private lateinit var activityController: ActivityController<RequestPermissionActivity>
+ private lateinit var bluetoothAdapter: ShadowBluetoothAdapter
+
+ @Before
+ fun setUp() {
+ bluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter())
+ }
+
+ @After
+ fun tearDown() {
+ activityController.pause().stop().destroy()
+ ShadowAlertDialogCompat.reset()
+ }
+
+ @Test
+ fun requestEnable_whenBluetoothIsOff_showConfirmDialog() {
+ bluetoothAdapter.setState(BluetoothAdapter.STATE_OFF)
+
+ createActivity(action = BluetoothAdapter.ACTION_REQUEST_ENABLE)
+
+ val dialog = ShadowAlertDialogCompat.getLatestAlertDialog()
+ val shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog)
+ assertThat(shadowDialog.message.toString())
+ .isEqualTo("An app wants to turn on Bluetooth")
+ }
+
+ @Test
+ fun requestEnable_whenBluetoothIsOn_doNothing() {
+ bluetoothAdapter.setState(BluetoothAdapter.STATE_ON)
+
+ createActivity(action = BluetoothAdapter.ACTION_REQUEST_ENABLE)
+
+ val dialog = ShadowAlertDialogCompat.getLatestAlertDialog()
+ assertThat(dialog).isNull()
+ }
+
+ @Test
+ fun requestDisable_whenBluetoothIsOff_doNothing() {
+ bluetoothAdapter.setState(BluetoothAdapter.STATE_OFF)
+
+ createActivity(action = BluetoothAdapter.ACTION_REQUEST_DISABLE)
+
+ val dialog = ShadowAlertDialogCompat.getLatestAlertDialog()
+ assertThat(dialog).isNull()
+ }
+
+ @Test
+ fun requestDisable_whenBluetoothIsOn_showConfirmDialog() {
+ bluetoothAdapter.setState(BluetoothAdapter.STATE_ON)
+
+ createActivity(action = BluetoothAdapter.ACTION_REQUEST_DISABLE)
+
+ val dialog = ShadowAlertDialogCompat.getLatestAlertDialog()
+ val shadowDialog = ShadowAlertDialogCompat.shadowOf(dialog)
+ assertThat(shadowDialog.message.toString())
+ .isEqualTo("An app wants to turn off Bluetooth")
+ }
+
+ private fun createActivity(action: String) {
+ activityController =
+ ActivityController.of(RequestPermissionActivity(), Intent(action)).apply {
+ create()
+ start()
+ postCreate(null)
+ resume()
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionHelperTest.kt b/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionHelperTest.kt
index ce0792c..e51a2f9 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionHelperTest.kt
+++ b/tests/robotests/src/com/android/settings/bluetooth/RequestPermissionHelperTest.kt
@@ -49,13 +49,14 @@
@Test
fun requestEnable_withAppLabelAndNoTimeout_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestEnable(
context = activity,
appLabel = "App Label",
timeout = -1,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs("App Label wants to turn on Bluetooth")
}
@@ -63,13 +64,14 @@
@Test
fun requestEnable_withAppLabelAndZeroTimeout_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestEnable(
context = activity,
appLabel = "App Label",
timeout = 0,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs(
"App Label wants to turn on Bluetooth and make your phone visible to other devices. " +
@@ -80,13 +82,14 @@
@Test
fun requestEnable_withAppLabelAndNormalTimeout_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestEnable(
context = activity,
appLabel = "App Label",
timeout = 120,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs(
"App Label wants to turn on Bluetooth and make your phone visible to other devices " +
@@ -97,13 +100,14 @@
@Test
fun requestEnable_withNoAppLabelAndNoTimeout_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestEnable(
context = activity,
appLabel = null,
timeout = -1,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs("An app wants to turn on Bluetooth")
}
@@ -111,13 +115,14 @@
@Test
fun requestEnable_withNoAppLabelAndZeroTimeout_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestEnable(
context = activity,
appLabel = null,
timeout = 0,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs(
"An app wants to turn on Bluetooth and make your phone visible to other devices. " +
@@ -128,13 +133,14 @@
@Test
fun requestEnable_withNoAppLabelAndNormalTimeout_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestEnable(
context = activity,
appLabel = null,
timeout = 120,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs(
"An app wants to turn on Bluetooth and make your phone visible to other devices for " +
@@ -177,12 +183,13 @@
@Test
fun requestDisable_withAppLabel_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestDisable(
context = activity,
appLabel = "App Label",
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs("App Label wants to turn off Bluetooth")
}
@@ -190,12 +197,13 @@
@Test
fun requestDisable_withNoAppLabel_hasCorrectMessage() {
val activity = activityController.get()
+
RequestPermissionHelper.requestDisable(
context = activity,
appLabel = null,
onAllow = {},
onDeny = {},
- )
+ )!!.show()
assertLatestMessageIs("An app wants to turn off Bluetooth")
}
diff --git a/tests/robotests/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceControllerTest.java
new file mode 100644
index 0000000..b405f9e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/development/BluetoothLeAudioDeviceDetailsPreferenceControllerTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothStatusCodes;
+import android.content.Context;
+import android.provider.DeviceConfig;
+
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.core.SettingsUIDeviceConfig;
+import com.android.settings.testutils.shadow.ShadowDeviceConfig;
+
+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 org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowDeviceConfig.class})
+public class BluetoothLeAudioDeviceDetailsPreferenceControllerTest {
+
+ @Mock
+ private PreferenceScreen mPreferenceScreen;
+ @Mock
+ private BluetoothAdapter mBluetoothAdapter;
+ @Mock
+ private SwitchPreference mPreference;
+
+ private Context mContext;
+ private BluetoothLeAudioDeviceDetailsPreferenceController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ mContext = RuntimeEnvironment.application;
+ mController = spy(new BluetoothLeAudioDeviceDetailsPreferenceController(mContext));
+ when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
+ .thenReturn(mPreference);
+ mController.mBluetoothAdapter = mBluetoothAdapter;
+ mController.displayPreference(mPreferenceScreen);
+ }
+
+ @After
+ public void tearDown() {
+ ShadowDeviceConfig.reset();
+ }
+
+ @Test
+ public void onPreferenceChanged_settingEnabled_shouldTurnOnLeAudioDeviceDetailSetting() {
+ mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
+ mController.onPreferenceChange(mPreference, true /* new value */);
+ final boolean isEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SETTINGS_UI,
+ SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
+
+ assertThat(isEnabled).isTrue();
+ }
+
+ @Test
+ public void onPreferenceChanged_settingDisabled_shouldTurnOffLeAudioDeviceDetailSetting() {
+ mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
+ mController.onPreferenceChange(mPreference, false /* new value */);
+ final boolean isEnabled = DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_SETTINGS_UI,
+ SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, false);
+
+ assertThat(isEnabled).isFalse();
+ }
+
+ @Test
+ public void updateState_settingEnabled_preferenceShouldBeChecked() {
+ mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
+ SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "true", false);
+ mController.updateState(mPreference);
+
+ verify(mPreference).setChecked(true);
+ }
+
+ @Test
+ public void updateState_settingDisabled_preferenceShouldNotBeChecked() {
+ mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.FEATURE_SUPPORTED;
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_UI,
+ SettingsUIDeviceConfig.BT_LE_AUDIO_DEVICE_DETAIL_ENABLED, "false", false);
+ mController.updateState(mPreference);
+
+ verify(mPreference).setChecked(false);
+ }
+
+ @Test
+ public void isAvailable_leAudioSupported() {
+ mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.ERROR_UNKNOWN;
+ when(mBluetoothAdapter.isLeAudioSupported())
+ .thenReturn(BluetoothStatusCodes.FEATURE_SUPPORTED);
+ assertThat(mController.isAvailable()).isTrue();
+ }
+
+ @Test
+ public void isAvailable_leAudioNotSupported() {
+ mController.sLeAudioSupportedStateCache = BluetoothStatusCodes.ERROR_UNKNOWN;
+ when(mBluetoothAdapter.isLeAudioSupported())
+ .thenReturn(BluetoothStatusCodes.FEATURE_NOT_SUPPORTED);
+ assertThat(mController.isAvailable()).isFalse();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogControllerTest.java
index a396a92..89cc6d9 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogControllerTest.java
@@ -39,7 +39,6 @@
import android.telephony.TelephonyManager;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -197,11 +196,10 @@
}
@Test
- @Ignore
public void populateImeiInfo_emptyImei_shouldSetMeid_imeiSetToEmptyString() {
doReturn(true).when(mController).isCdmaLteEnabled();
when(mTelephonyManager.getPhoneType()).thenReturn(TelephonyManager.PHONE_TYPE_CDMA);
- when(mTelephonyManager.getImei(anyInt())).thenReturn(null);
+ when(mTelephonyManager.getImei(anyInt())).thenReturn("");
mController.populateImeiInfo();
diff --git a/tests/robotests/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceControllerTest.java
index b4cb862..a99abb8 100644
--- a/tests/robotests/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/inputmethod/TrackpadReverseScrollingPreferenceControllerTest.java
@@ -61,7 +61,7 @@
}
@Test
- public void setChecked_true_shouldReturn1() {
+ public void setChecked_true_shouldReturn0() {
mController.setChecked(true);
int result = Settings.System.getIntForUser(
@@ -70,24 +70,24 @@
0,
UserHandle.USER_CURRENT);
- assertThat(result).isEqualTo(1);
- }
-
- @Test
- public void setChecked_false_shouldReturn0() {
- mController.setChecked(false);
-
- int result = Settings.System.getIntForUser(
- mContext.getContentResolver(),
- SETTING_KEY,
- 0,
- UserHandle.USER_CURRENT);
-
assertThat(result).isEqualTo(0);
}
@Test
- public void isChecked_providerPutInt1_returnTrue() {
+ public void setChecked_false_shouldReturn1() {
+ mController.setChecked(false);
+
+ int result = Settings.System.getIntForUser(
+ mContext.getContentResolver(),
+ SETTING_KEY,
+ 0,
+ UserHandle.USER_CURRENT);
+
+ assertThat(result).isEqualTo(1);
+ }
+
+ @Test
+ public void isChecked_providerPutInt1_returnFalse() {
Settings.System.putIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
@@ -96,11 +96,11 @@
boolean result = mController.isChecked();
- assertThat(result).isTrue();
+ assertThat(result).isFalse();
}
@Test
- public void isChecked_providerPutInt0_returnFalse() {
+ public void isChecked_providerPutInt0_returnTrue() {
Settings.System.putIntForUser(
mContext.getContentResolver(),
SETTING_KEY,
@@ -109,6 +109,6 @@
boolean result = mController.isChecked();
- assertThat(result).isFalse();
+ assertThat(result).isTrue();
}
}
diff --git a/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt b/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
index 46b956e..1b2a7b1 100644
--- a/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/SpaActivityTest.kt
@@ -21,33 +21,71 @@
import android.net.Uri
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.settings.spa.SpaActivity.Companion.isSuwAndPageBlocked
import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
import com.android.settings.spa.SpaActivity.Companion.startSpaActivityForApp
+import com.android.settings.spa.app.AllAppListPageProvider
+import com.android.settings.spa.app.appinfo.AppInfoSettingsProvider
import com.android.settingslib.spa.framework.util.KEY_DESTINATION
+import com.google.android.setupcompat.util.WizardManagerHelper
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
-import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.Answers
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
-import org.mockito.junit.MockitoJUnit
-import org.mockito.junit.MockitoRule
+import org.mockito.MockitoSession
+import org.mockito.quality.Strictness
+import org.mockito.Mockito.`when` as whenever
@RunWith(AndroidJUnit4::class)
class SpaActivityTest {
- @get:Rule
- val mockito: MockitoRule = MockitoJUnit.rule()
+ private lateinit var mockSession: MockitoSession
- @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ @Mock
private lateinit var context: Context
@Before
fun setUp() {
- `when`(context.applicationContext.packageName).thenReturn("com.android.settings")
+ mockSession = ExtendedMockito.mockitoSession()
+ .initMocks(this)
+ .mockStatic(WizardManagerHelper::class.java)
+ .strictness(Strictness.LENIENT)
+ .startMocking()
+ whenever(context.applicationContext).thenReturn(context)
+ }
+
+ @After
+ fun tearDown() {
+ mockSession.finishMocking()
+ }
+
+ @Test
+ fun isSuwAndPageBlocked_regularPage_notBlocked() {
+ val isBlocked = context.isSuwAndPageBlocked(AllAppListPageProvider.name)
+
+ assertThat(isBlocked).isFalse()
+ }
+
+ @Test
+ fun isSuwAndPageBlocked_blocklistedPageInSuw_blocked() {
+ whenever(WizardManagerHelper.isDeviceProvisioned(context)).thenReturn(false)
+
+ val isBlocked = context.isSuwAndPageBlocked(AppInfoSettingsProvider.name)
+
+ assertThat(isBlocked).isTrue()
+ }
+
+ @Test
+ fun isSuwAndPageBlocked_blocklistedPageNotInSuw_notBlocked() {
+ whenever(WizardManagerHelper.isDeviceProvisioned(context)).thenReturn(true)
+
+ val isBlocked = context.isSuwAndPageBlocked(AppInfoSettingsProvider.name)
+
+ assertThat(isBlocked).isFalse()
}
@Test
diff --git a/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java b/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java
index f954ea4..1043fdf 100644
--- a/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/MobileNetworkUtilsTest.java
@@ -385,35 +385,19 @@
}
@Test
- public void isWifiCallingEnabled_hasPhoneAccountHandleAndHasActivityHandleIntent_returnTrue() {
- buildPhoneAccountConfigureIntent(true);
-
- assertTrue(MobileNetworkUtils.isWifiCallingEnabled(mContext, SUB_ID_1,
- null, mPhoneAccountHandle));
- }
-
- @Test
- public void isWifiCallingEnabled_hasPhoneAccountHandleAndNoActivityHandleIntent_returnFalse() {
- buildPhoneAccountConfigureIntent(false);
-
- assertFalse(MobileNetworkUtils.isWifiCallingEnabled(mContext, SUB_ID_1,
- null, mPhoneAccountHandle));
- }
-
- @Test
- public void isWifiCallingEnabled_noPhoneAccountHandleAndWifiCallingIsReady_returnTrue() {
+ public void isWifiCallingEnabled_wifiCallingIsReady_returnTrue() {
setWifiCallingEnabled(true);
assertTrue(MobileNetworkUtils.isWifiCallingEnabled(mContext, SUB_ID_1,
- mMockQueryWfcState, null));
+ mMockQueryWfcState));
}
@Test
- public void isWifiCallingEnabled_noPhoneAccountHandleAndWifiCallingNotReady_returnFalse() {
+ public void isWifiCallingEnabled_wifiCallingNotReady_returnFalse() {
setWifiCallingEnabled(false);
assertFalse(MobileNetworkUtils.isWifiCallingEnabled(mContext, SUB_ID_1,
- mMockQueryWfcState, null));
+ mMockQueryWfcState));
}
private void setWifiCallingEnabled(boolean enabled){