Merge "Add SafeSites related content filters preference." into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index bbe7963..8f5699c 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1899,7 +1899,7 @@
<activity android:name="Settings$UserAspectRatioAppListActivity"
android:exported="true"
- android:label="@string/aspect_ratio_experimental_title">
+ android:label="@string/aspect_ratio_title">
<intent-filter android:priority="1">
<action android:name="android.settings.MANAGE_USER_ASPECT_RATIO_SETTINGS"/>
<category android:name="android.intent.category.DEFAULT" />
@@ -1912,7 +1912,7 @@
<activity android:name="Settings$UserAspectRatioAppActivity"
android:exported="true"
- android:label="@string/aspect_ratio_experimental_title">
+ android:label="@string/aspect_ratio_title">
<intent-filter>
<action android:name="android.settings.MANAGE_USER_ASPECT_RATIO_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/aconfig/settings_bluetooth_declarations.aconfig b/aconfig/settings_bluetooth_declarations.aconfig
index 7f30895..e2edcb5 100644
--- a/aconfig/settings_bluetooth_declarations.aconfig
+++ b/aconfig/settings_bluetooth_declarations.aconfig
@@ -58,7 +58,7 @@
flag {
name: "enable_remove_association_bt_unpair"
is_exported: true
- namespace: "companion_device_manager"
+ namespace: "companion"
description: "Allow to disassociate when to forget a BT pair device"
bug: "365613753"
}
diff --git a/res/drawable/device_details_spotlight_preference_background.xml b/res/drawable/device_details_spotlight_preference_background.xml
new file mode 100644
index 0000000..58a29a1
--- /dev/null
+++ b/res/drawable/device_details_spotlight_preference_background.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 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.
+-->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:colorControlHighlight">
+ <item>
+ <shape android:shape="rectangle">
+ <solid
+ android:color="@color/settingslib_materialColorSecondaryContainer" />
+ <corners
+ android:radius="28dp" />
+ </shape>
+ </item>
+</ripple>
diff --git a/res/layout/bluetooth_device_spotlight_preference.xml b/res/layout/bluetooth_device_spotlight_preference.xml
new file mode 100644
index 0000000..ee2778a
--- /dev/null
+++ b/res/layout/bluetooth_device_spotlight_preference.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2025 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.
+-->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingEnd="?android:attr/scrollbarSize"
+ android:background="?android:attr/selectableItemBackground">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginHorizontal="16dp"
+ android:background="@drawable/device_details_spotlight_preference_background" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:gravity="center_vertical">
+
+ <ImageView
+ android:id="@+android:id/icon"
+ android:layout_width="24dip"
+ android:layout_height="24dip"
+ android:layout_gravity="center"
+ android:scaleType="center"
+ android:importantForAccessibility="no" />
+
+ <RelativeLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="24dp"
+ android:layout_marginEnd="6dp"
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="6dp"
+ android:layout_weight="1">
+
+ <TextView android:id="@+android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal" />
+
+ <TextView android:id="@+android:id/summary"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/title"
+ android:layout_alignStart="@android:id/title"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="4" />
+ </RelativeLayout>
+ </LinearLayout>
+</FrameLayout>
diff --git a/res/layout/bluetooth_pin_confirm.xml b/res/layout/bluetooth_pin_confirm.xml
index 9387d5d..69ea777 100644
--- a/res/layout/bluetooth_pin_confirm.xml
+++ b/res/layout/bluetooth_pin_confirm.xml
@@ -101,7 +101,8 @@
android:hyphenationFrequency="normalFast"
android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Caption" />
</LinearLayout>
- <Switch
+ <com.google.android.material.materialswitch.MaterialSwitch
+ android:theme="@style/Theme.Material3.DynamicColors.DayNight"
android:id="@+id/phonebook_sharing_message_confirm_pin"
android:layout_width="wrap_content"
android:layout_height="48dp"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 1e8ba4e..79020f9 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -13189,6 +13189,11 @@
<!-- [CHAR LIMIT=200] Manage applications, text for dialog when killing persistent apps-->
<string name="stop_app_dlg_text">Application will be stopped to apply page size compat setting.</string>
+ <!-- Error messages for 16 KB Developer option-->
+ <string name="error_pending_updates">Kernel update failed. Check and install any pending updates.</string>
+
+ <string name="error_ota_failed">Kernel update failed. Error occurred while applying OTA.</string>
+
<!-- DSU Loader. Do not translate. -->
<string name="dsu_loader_title" translatable="false">DSU Loader</string>
@@ -13836,20 +13841,6 @@
<!-- [CHAR LIMIT=NONE] Warning description for app info aspect ratio page -->
<string name="app_aspect_ratio_footer">The app will restart when you change aspect ratio. You may lose unsaved changes. Some apps may not be optimized for certain aspect ratios.</string>
- <!-- TODO(b/300219974): Change aspect ratio title and clean up unused titles -->
- <!-- [CHAR LIMIT=60] Aspect ratio experimental title settings to choose app aspect ratio -->
- <string name="aspect_ratio_experimental_title">Aspect ratio (experimental)</string>
- <!-- [CHAR LIMIT=60] Aspect ratio experiment title settings to choose app aspect ratio -->
- <string name="aspect_ratio_experiment_title">Aspect ratio (experiment)</string>
- <!-- [CHAR LIMIT=60] Aspect ratio labs title settings to choose app aspect ratio -->
- <string name="aspect_ratio_labs_title">Aspect ratio (labs)</string>
- <!-- [CHAR LIMIT=60] Aspect ratio experimental title label -->
- <string name="aspect_ratio_experimental_label">Experimental</string>
- <!-- [CHAR LIMIT=60] Aspect ratio experiment title label -->
- <string name="aspect_ratio_experiment_label">Experiment</string>
- <!-- [CHAR LIMIT=60] Aspect ratio labs title label -->
- <string name="aspect_ratio_labs_label">Labs</string>
-
<!-- Accessibility label for fingerprint sensor [CHAR LIMIT=NONE] -->
<string name="accessibility_fingerprint_label">Fingerprint sensor</string>
diff --git a/res/xml/apps.xml b/res/xml/apps.xml
index 77b210f..b687497 100644
--- a/res/xml/apps.xml
+++ b/res/xml/apps.xml
@@ -123,7 +123,7 @@
<Preference
android:key="aspect_ratio_apps"
- android:title="@string/aspect_ratio_experimental_title"
+ android:title="@string/aspect_ratio_title"
android:summary="@string/summary_placeholder"
android:order="22"
settings:controller="com.android.settings.applications.appcompat.UserAspectRatioAppsPreferenceController"
diff --git a/res/xml/user_aspect_ratio_details.xml b/res/xml/user_aspect_ratio_details.xml
index 24c3271..af3d2d5 100644
--- a/res/xml/user_aspect_ratio_details.xml
+++ b/res/xml/user_aspect_ratio_details.xml
@@ -19,7 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
- android:title="@string/aspect_ratio_experimental_title">
+ android:title="@string/aspect_ratio_title">
<com.android.settingslib.widget.TopIntroPreference
android:key="app_aspect_ratio_summary"
diff --git a/src/com/android/settings/accessibility/AccessibilitySettings.java b/src/com/android/settings/accessibility/AccessibilitySettings.java
index 2c8247f..b4b1ef6 100644
--- a/src/com/android/settings/accessibility/AccessibilitySettings.java
+++ b/src/com/android/settings/accessibility/AccessibilitySettings.java
@@ -30,9 +30,6 @@
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.NonNull;
@@ -45,6 +42,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.settings.R;
import com.android.settings.accessibility.AccessibilityUtil.AccessibilityServiceFragmentType;
+import com.android.settings.accessibility.actionbar.FeedbackMenuController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.search.BaseSearchIndexProvider;
@@ -105,8 +103,6 @@
// presentation.
private static final long DELAY_UPDATE_SERVICES_MILLIS = 1000;
- static final int MENU_ID_SEND_FEEDBACK = 0;
-
private final Handler mHandler = new Handler();
private final Runnable mUpdateRunnable = new Runnable() {
@@ -151,8 +147,6 @@
private AccessibilitySettingsContentObserver mSettingsContentObserver;
- private FeedbackManager mFeedbackManager;
-
private final Map<String, PreferenceCategory> mCategoryToPrefCategoryMap =
new ArrayMap<>();
private final List<Preference> mServicePreferences = new ArrayList<>();
@@ -216,6 +210,7 @@
mNeedPreferencesUpdate = false;
registerContentMonitors();
registerInputDeviceListener();
+ FeedbackMenuController.init(this, SettingsEnums.ACCESSIBILITY);
}
@Override
@@ -253,24 +248,6 @@
}
@Override
- public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
- if (getFeedbackManager().isAvailable()) {
- menu.add(Menu.NONE, MENU_ID_SEND_FEEDBACK, Menu.NONE,
- R.string.accessibility_send_feedback_title);
- }
- super.onCreateOptionsMenu(menu, inflater);
- }
-
- @Override
- public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- if (item.getItemId() == MENU_ID_SEND_FEEDBACK) {
- getFeedbackManager().sendFeedback();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
protected int getPreferenceScreenResId() {
return R.xml.accessibility_settings;
}
@@ -280,18 +257,6 @@
return TAG;
}
- @VisibleForTesting
- void setFeedbackManager(FeedbackManager feedbackManager) {
- this.mFeedbackManager = feedbackManager;
- }
-
- private FeedbackManager getFeedbackManager() {
- if (mFeedbackManager == null) {
- mFeedbackManager = new FeedbackManager(getActivity(), SettingsEnums.ACCESSIBILITY);
- }
- return mFeedbackManager;
- }
-
/**
* Returns the summary for the current state of this accessibilityService.
*
diff --git a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
index d8c3985..367f557 100644
--- a/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.java
@@ -40,9 +40,6 @@
import android.text.Html;
import android.text.TextUtils;
import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
@@ -63,6 +60,7 @@
import com.android.internal.accessibility.util.ShortcutUtils;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.accessibility.actionbar.FeedbackMenuController;
import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.flags.Flags;
@@ -94,7 +92,6 @@
// <img src="R.drawable.fileName"/>, a11y settings will get the resources successfully.
private static final String IMG_PREFIX = "R.drawable.";
private static final String DRAWABLE_FOLDER = "drawable";
- static final int MENU_ID_SEND_FEEDBACK = 0;
protected TopIntroPreference mTopIntroPreference;
protected SettingsMainSwitchPreference mToggleServiceSwitchPreference;
@@ -108,7 +105,6 @@
protected Intent mSettingsIntent;
// The mComponentName maybe null, such as Magnify
protected ComponentName mComponentName;
- @Nullable private FeedbackManager mFeedbackManager;
protected CharSequence mFeatureName;
protected Uri mImageUri;
protected CharSequence mHtmlDescription;
@@ -142,6 +138,8 @@
mSettingsContentObserver = new AccessibilitySettingsContentObserver(new Handler());
registerKeysToObserverCallback(mSettingsContentObserver);
+
+ FeedbackMenuController.init(this, getFeedbackCategory());
}
protected void registerKeysToObserverCallback(
@@ -248,24 +246,6 @@
}
@Override
- public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
- if (getFeedbackManager().isAvailable()) {
- menu.add(Menu.NONE, MENU_ID_SEND_FEEDBACK, Menu.NONE,
- R.string.accessibility_send_feedback_title);
- }
- super.onCreateOptionsMenu(menu, inflater);
- }
-
- @Override
- public boolean onOptionsItemSelected(@NonNull MenuItem item) {
- if (item.getItemId() == MENU_ID_SEND_FEEDBACK) {
- getFeedbackManager().sendFeedback();
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- @Override
public int getDialogMetricsCategory(int dialogId) {
switch (dialogId) {
case DialogEnums.LAUNCH_ACCESSIBILITY_TUTORIAL:
@@ -280,6 +260,18 @@
return SettingsEnums.ACCESSIBILITY_SERVICE;
}
+ /**
+ * Returns the category of the feedback page.
+ *
+ * <p>By default, this method returns {@link SettingsEnums#PAGE_UNKNOWN}. This indicates that
+ * the feedback category is unknown, and the absence of a feedback menu.
+ *
+ * @return The feedback category, which is {@link SettingsEnums#PAGE_UNKNOWN} by default.
+ */
+ protected int getFeedbackCategory() {
+ return SettingsEnums.PAGE_UNKNOWN;
+ }
+
@Override
public int getHelpResource() {
return 0;
@@ -785,28 +777,4 @@
super.onCreateRecyclerView(inflater, parent, savedInstanceState);
return AccessibilityFragmentUtils.addCollectionInfoToAccessibilityDelegate(recyclerView);
}
-
- @VisibleForTesting
- void setFeedbackManager(FeedbackManager feedbackManager) {
- this.mFeedbackManager = feedbackManager;
- }
-
- private FeedbackManager getFeedbackManager() {
- if (mFeedbackManager == null) {
- mFeedbackManager = new FeedbackManager(getActivity(), getFeedbackCategory());
- }
- return mFeedbackManager;
- }
-
- /**
- * Returns the category of the feedback page.
- *
- * <p>By default, this method returns {@link SettingsEnums#PAGE_UNKNOWN}. This indicates that
- * the feedback category is unknown, and the absence of a feedback menu.
- *
- * @return The feedback category, which is {@link SettingsEnums#PAGE_UNKNOWN} by default.
- */
- protected int getFeedbackCategory() {
- return SettingsEnums.PAGE_UNKNOWN;
- }
}
diff --git a/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt b/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt
index c488e27..4008cee 100644
--- a/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt
+++ b/src/com/android/settings/accessibility/VibrationMainSwitchPreference.kt
@@ -25,7 +25,7 @@
import com.android.settings.contract.KEY_VIBRATION_HAPTICS
import com.android.settings.metrics.PreferenceActionMetricsProvider
import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.KeyValueStoreDelegate
import com.android.settingslib.datastore.SettingsSystemStore
import com.android.settingslib.metadata.BooleanValuePreference
import com.android.settingslib.metadata.PreferenceMetadata
@@ -96,18 +96,13 @@
class VibrationMainSwitchStore(
context: Context,
private val settingsStore: KeyValueStore = SettingsSystemStore.get(context),
-) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+) : KeyValueStoreDelegate {
- override fun contains(key: String) = settingsStore.contains(key)
+ override val keyValueStoreDelegate
+ get() = settingsStore
override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) = DEFAULT_VALUE as T
- override fun <T : Any> getValue(key: String, valueType: Class<T>) =
- settingsStore.getValue(key, valueType) ?: getDefaultValue(key, valueType)
-
- override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) =
- settingsStore.setValue(key, valueType, value)
-
companion object {
private const val DEFAULT_VALUE = true
}
diff --git a/src/com/android/settings/accessibility/actionbar/FeedbackMenuController.java b/src/com/android/settings/accessibility/actionbar/FeedbackMenuController.java
new file mode 100644
index 0000000..ee08276
--- /dev/null
+++ b/src/com/android/settings/accessibility/actionbar/FeedbackMenuController.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2025 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.actionbar;
+
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+
+import androidx.annotation.NonNull;
+
+import com.android.settings.R;
+import com.android.settings.accessibility.FeedbackManager;
+import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu;
+import com.android.settingslib.core.lifecycle.events.OnOptionsItemSelected;
+
+/**
+ * A controller that adds feedback menu to any Settings page.
+ */
+public class FeedbackMenuController implements LifecycleObserver, OnCreateOptionsMenu,
+ OnOptionsItemSelected {
+
+ /**
+ * The menu item ID for the feedback menu option.
+ */
+ public static final int MENU_FEEDBACK = Menu.FIRST + 10;
+
+ /**
+ * The menu item ID for the feedback menu option.
+ */
+ private final FeedbackManager mFeedbackManager;
+
+ /**
+ * Initializes the FeedbackMenuController for an InstrumentedPreferenceFragment with a provided
+ * pade ID.
+ *
+ * @param host The InstrumentedPreferenceFragment to which the menu controller will be added.
+ * @param pageId The page ID used for feedback tracking.
+ */
+ public static void init(@NonNull InstrumentedPreferenceFragment host, int pageId) {
+ host.getSettingsLifecycle().addObserver(
+ new FeedbackMenuController(
+ new FeedbackManager(host.getActivity(), pageId)));
+ }
+
+ /**
+ * Initializes the FeedbackMenuController for an InstrumentedPreferenceFragment with a provided
+ * FeedbackManager.
+ *
+ * @param host The InstrumentedPreferenceFragment to which the menu controller will be added.
+ * @param feedbackManager The FeedbackManager to use for handling feedback actions.
+ */
+ public static void init(@NonNull InstrumentedPreferenceFragment host,
+ @NonNull FeedbackManager feedbackManager) {
+ host.getSettingsLifecycle().addObserver(
+ new FeedbackMenuController(feedbackManager));
+ }
+
+ @Override
+ public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
+ if (!mFeedbackManager.isAvailable()) {
+ return;
+ }
+ menu.add(Menu.NONE, MENU_FEEDBACK, Menu.NONE, R.string.accessibility_send_feedback_title);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem menuItem) {
+ if (menuItem.getItemId() == MENU_FEEDBACK) {
+ mFeedbackManager.sendFeedback();
+ return true;
+ }
+ return false;
+ }
+
+ private FeedbackMenuController(@NonNull FeedbackManager feedbackManager) {
+ mFeedbackManager = feedbackManager;
+ }
+}
diff --git a/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java b/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java
index 9fe4794..6be6a38 100644
--- a/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java
+++ b/src/com/android/settings/biometrics/combination/CombinedBiometricSettings.java
@@ -204,5 +204,11 @@
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new CombinedBiometricSearchIndexProvider(R.xml.security_settings_combined_biometric);
+ new CombinedBiometricSearchIndexProvider(R.xml.security_settings_combined_biometric) {
+ @Override
+ protected boolean isPageSearchEnabled(Context context) {
+ return super.isPageSearchEnabled(context)
+ && !Flags.biometricsOnboardingEducation();
+ }
+ };
}
diff --git a/src/com/android/settings/biometrics/face/FaceEnroll.kt b/src/com/android/settings/biometrics/face/FaceEnroll.kt
index 2ed628d..74f1613 100644
--- a/src/com/android/settings/biometrics/face/FaceEnroll.kt
+++ b/src/com/android/settings/biometrics/face/FaceEnroll.kt
@@ -23,7 +23,6 @@
import androidx.appcompat.app.AppCompatActivity
import com.android.settings.biometrics.BiometricEnrollBase.RESULT_FINISHED
import com.android.settings.biometrics.combination.CombinedBiometricStatusUtils
-
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
class FaceEnroll: AppCompatActivity() {
@@ -39,18 +38,33 @@
private val enrollActivityProvider: FaceEnrollActivityClassProvider
get() = featureFactory.faceFeatureProvider.enrollActivityClassProvider
+ private var isLaunched = false
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- /**
- * Logs the next activity to be launched, creates an intent for that activity,
- * adds flags to forward the result, includes any existing extras from the current intent,
- * starts the new activity and then finishes the current one
- */
- Log.d("FaceEnroll", "forward to $nextActivityClass")
- val nextIntent = Intent(this, nextActivityClass)
- nextIntent.putExtras(intent)
- startActivityForResult(nextIntent, 0)
+ if (savedInstanceState != null) {
+ isLaunched = savedInstanceState.getBoolean(KEY_IS_LAUNCHED, isLaunched)
+ }
+
+ if (!isLaunched) {
+ /**
+ * Logs the next activity to be launched, creates an intent for that activity,
+ * adds flags to forward the result, includes any existing extras from the current intent,
+ * starts the new activity and then finishes the current one
+ */
+ Log.d("FaceEnroll", "forward to $nextActivityClass")
+ val nextIntent = Intent(this, nextActivityClass)
+ nextIntent.putExtras(intent)
+ startActivityForResult(nextIntent, 0)
+
+ isLaunched = true
+ }
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ outState.putBoolean(KEY_IS_LAUNCHED, isLaunched)
+ super.onSaveInstanceState(outState)
}
override fun onActivityResult(
@@ -60,6 +74,7 @@
caller: ComponentCaller
) {
super.onActivityResult(requestCode, resultCode, data, caller)
+ isLaunched = false
if (intent.getBooleanExtra(
CombinedBiometricStatusUtils.EXTRA_LAUNCH_FROM_SAFETY_SOURCE_ISSUE, false)
&& resultCode != RESULT_FINISHED) {
@@ -68,4 +83,8 @@
setResult(resultCode, data)
finish()
}
-}
\ No newline at end of file
+
+ private companion object {
+ const val KEY_IS_LAUNCHED = "isLaunched"
+ }
+}
diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintEnroll.kt b/src/com/android/settings/biometrics/fingerprint/FingerprintEnroll.kt
index 795be13..229f6c4 100644
--- a/src/com/android/settings/biometrics/fingerprint/FingerprintEnroll.kt
+++ b/src/com/android/settings/biometrics/fingerprint/FingerprintEnroll.kt
@@ -62,18 +62,33 @@
protected val enrollActivityProvider: FingerprintEnrollActivityClassProvider
get() = featureFactory.fingerprintFeatureProvider.getEnrollActivityClassProvider(this)
+ private var isLaunched = false
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- /**
- * Logs the next activity to be launched, creates an intent for that activity,
- * adds flags to forward the result, includes any existing extras from the current intent,
- * starts the new activity and then finishes the current one
- */
- Log.d("FingerprintEnroll", "forward to $nextActivityClass")
- val nextIntent = Intent(this, nextActivityClass)
- nextIntent.putExtras(intent)
- startActivityForResult(nextIntent, 0)
+ if (savedInstanceState != null) {
+ isLaunched = savedInstanceState.getBoolean(KEY_IS_LAUNCHED, isLaunched)
+ }
+
+ if (!isLaunched) {
+ /**
+ * Logs the next activity to be launched, creates an intent for that activity,
+ * adds flags to forward the result, includes any existing extras from the current intent,
+ * starts the new activity and then finishes the current one
+ */
+ Log.d("FingerprintEnroll", "forward to $nextActivityClass")
+ val nextIntent = Intent(this, nextActivityClass)
+ nextIntent.putExtras(intent)
+ startActivityForResult(nextIntent, 0)
+
+ isLaunched = true
+ }
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ outState.putBoolean(KEY_IS_LAUNCHED, isLaunched)
+ super.onSaveInstanceState(outState)
}
override fun onActivityResult(
@@ -83,6 +98,7 @@
caller: ComponentCaller
) {
super.onActivityResult(requestCode, resultCode, data, caller)
+ isLaunched = false
if (intent.getBooleanExtra(
CombinedBiometricStatusUtils.EXTRA_LAUNCH_FROM_SAFETY_SOURCE_ISSUE, false)
&& resultCode != BiometricEnrollBase.RESULT_FINISHED
@@ -92,4 +108,8 @@
setResult(resultCode, data)
finish()
}
+
+ private companion object {
+ const val KEY_IS_LAUNCHED = "isLaunched"
+ }
}
\ No newline at end of file
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
index 9d54b1d..476f002 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
@@ -250,17 +250,19 @@
TextView messageViewCaptionHint = (TextView) view.findViewById(R.id.pin_values_hint);
TextView messageView2 = (TextView) view.findViewById(R.id.message_below_pin);
CheckBox alphanumericPin = (CheckBox) view.findViewById(R.id.alphanumeric_pin);
- CheckBox contactSharing = (CheckBox) view.findViewById(
- R.id.phonebook_sharing_message_entry_pin);
- contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook));
+
+ CheckBox contactSharing =
+ (CheckBox) view.findViewById(R.id.phonebook_sharing_message_entry_pin);
+ if (contactSharing != null) {
+ contactSharing.setText(getString(R.string.bluetooth_pairing_shares_phonebook));
+ contactSharing.setVisibility(
+ mPairingController.isContactSharingVisible() ? View.VISIBLE : View.GONE);
+ mPairingController.setContactSharingState();
+ contactSharing.setOnCheckedChangeListener(mPairingController);
+ contactSharing.setChecked(mPairingController.getContactSharingState());
+ }
+
EditText pairingView = (EditText) view.findViewById(R.id.text);
-
- contactSharing.setVisibility(
- mPairingController.isContactSharingVisible() ? View.VISIBLE : View.GONE);
- mPairingController.setContactSharingState();
- contactSharing.setOnCheckedChangeListener(mPairingController);
- contactSharing.setChecked(mPairingController.getContactSharingState());
-
mPairingView = pairingView;
pairingView.setInputType(InputType.TYPE_CLASS_NUMBER);
diff --git a/src/com/android/settings/bluetooth/ui/layout/DeviceSettingLayout.kt b/src/com/android/settings/bluetooth/ui/layout/DeviceSettingLayout.kt
deleted file mode 100644
index 5987e5a..0000000
--- a/src/com/android/settings/bluetooth/ui/layout/DeviceSettingLayout.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.bluetooth.ui.layout
-
-import kotlinx.coroutines.flow.Flow
-
-/** Represent the layout of device settings. */
-data class DeviceSettingLayout(val rows: List<DeviceSettingLayoutRow>)
-
-/** Represent a row in the layout. */
-data class DeviceSettingLayoutRow(val columns: Flow<List<DeviceSettingLayoutColumn>>)
-
-/** Represent a column in a row. */
-data class DeviceSettingLayoutColumn(val settingId: Int, val highlighted: Boolean)
diff --git a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
index b7ec32e..0658b1d 100644
--- a/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
+++ b/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatter.kt
@@ -21,35 +21,26 @@
import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.content.Intent
+import android.graphics.drawable.Drawable
import android.os.Bundle
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.unit.dp
+import androidx.core.graphics.drawable.toDrawable
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
+import androidx.preference.PreferenceViewHolder
+import androidx.preference.SwitchPreferenceCompat
+import androidx.preference.TwoStatePreference
import com.android.settings.R
import com.android.settings.bluetooth.BlockingPrefWithSliceController
import com.android.settings.bluetooth.BluetoothDetailsProfilesController
-import com.android.settings.bluetooth.ui.composable.Icon
import com.android.settings.bluetooth.ui.composable.MultiTogglePreference
-import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
import com.android.settings.bluetooth.ui.view.DeviceDetailsMoreSettingsFragment.Companion.KEY_DEVICE_ADDRESS
@@ -58,6 +49,7 @@
import com.android.settings.dashboard.DashboardFragment
import com.android.settings.overlay.FeatureFactory
import com.android.settings.spa.preference.ComposePreference
+import com.android.settingslib.PrimarySwitchPreference
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingActionModel
@@ -67,24 +59,15 @@
import com.android.settingslib.core.lifecycle.LifecycleObserver
import com.android.settingslib.core.lifecycle.events.OnPause
import com.android.settingslib.core.lifecycle.events.OnStop
-import com.android.settingslib.spa.framework.theme.SettingsDimension
-import com.android.settingslib.spa.widget.preference.Preference as SpaPreference
-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.preference.TwoTargetSwitchPreference
-import com.android.settingslib.spa.widget.ui.Footer
+import com.android.settingslib.widget.FooterPreference
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.emitAll
-import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@@ -105,7 +88,7 @@
@OptIn(ExperimentalCoroutinesApi::class)
class DeviceDetailsFragmentFormatterImpl(
private val context: Context,
- private val fragment: DashboardFragment,
+ private val dashboardFragment: DashboardFragment,
controllers: List<AbstractPreferenceController>,
private val bluetoothAdapter: BluetoothAdapter,
private val cachedDevice: CachedBluetoothDevice,
@@ -120,32 +103,30 @@
private val viewModel: BluetoothDeviceDetailsViewModel =
ViewModelProvider(
- fragment,
- BluetoothDeviceDetailsViewModel.Factory(
- fragment.requireActivity().application,
- bluetoothAdapter,
- cachedDevice,
- backgroundCoroutineContext,
- ),
- )
+ dashboardFragment,
+ BluetoothDeviceDetailsViewModel.Factory(
+ dashboardFragment.requireActivity().application,
+ bluetoothAdapter,
+ cachedDevice,
+ backgroundCoroutineContext,
+ ),
+ )
.get(BluetoothDeviceDetailsViewModel::class.java)
/** Updates bluetooth device details fragment layout. */
override fun updateLayout(fragmentType: FragmentTypeModel) {
- fragment.setLoading(true, false)
+ dashboardFragment.setLoading(true, false)
isLoading = true
- fragment.lifecycleScope.launch { updateLayoutInternal(fragmentType) }
+ dashboardFragment.lifecycleScope.launch { updateLayoutInternal(fragmentType) }
}
private suspend fun updateLayoutInternal(fragmentType: FragmentTypeModel) {
- val items = viewModel.getItems(fragmentType) ?: run {
- fragment.setLoading(false, false)
- return
- }
- val layout = viewModel.getLayout(fragmentType) ?: run {
- fragment.setLoading(false, false)
- return
- }
+ val items =
+ viewModel.getItems(fragmentType)
+ ?: run {
+ dashboardFragment.setLoading(false, false)
+ return
+ }
val prefKeyToSettingId =
items
@@ -153,14 +134,14 @@
.associateBy({ it.preferenceKey }, { it.settingId })
val settingIdToXmlPreferences: MutableMap<Int, Preference> = HashMap()
- for (i in 0 until fragment.preferenceScreen.preferenceCount) {
- val pref = fragment.preferenceScreen.getPreference(i)
+ for (i in 0 until dashboardFragment.preferenceScreen.preferenceCount) {
+ val pref = dashboardFragment.preferenceScreen.getPreference(i)
prefKeyToSettingId[pref.key]?.let { id -> settingIdToXmlPreferences[id] = pref }
if (pref.key !in prefKeyToSettingId) {
getController(pref.key)?.let { disableController(it) }
}
}
- fragment.preferenceScreen.removeAll()
+ dashboardFragment.preferenceScreen.removeAll()
for (job in prefVisibilityJobs) {
job.cancel()
}
@@ -170,53 +151,83 @@
val settingId = settingItem.settingId
if (settingIdToXmlPreferences.containsKey(settingId)) {
val pref = settingIdToXmlPreferences[settingId]!!.apply { order = row }
- fragment.preferenceScreen.addPreference(pref)
+ dashboardFragment.preferenceScreen.addPreference(pref)
} else {
val prefKey = getPreferenceKey(settingId)
+
prefVisibilityJobs.add(
- getDevicesSettingForRow(layout, row)
- .onEach { logItemShown(prefKey, it.isNotEmpty()) }
- .launchIn(fragment.lifecycleScope)
+ viewModel
+ .getDeviceSetting(cachedDevice, settingId)
+ .onEach { logItemShown(prefKey, it != null) }
+ .launchIn(dashboardFragment.lifecycleScope)
)
- val pref =
- ComposePreference(context)
- .apply {
- key = prefKey
- order = row
+ if (settingId == DeviceSettingId.DEVICE_SETTING_ID_ANC) {
+ // TODO(b/399316980): replace it with SegmentedButtonPreference once it's ready.
+ val pref =
+ ComposePreference(context)
+ .apply {
+ key = prefKey
+ order = row
+ }
+ .also { pref ->
+ pref.setContent {
+ buildComposePreference(cachedDevice, settingId, prefKey)
+ }
+ }
+ dashboardFragment.preferenceScreen.addPreference(pref)
+ } else {
+ viewModel
+ .getDeviceSetting(cachedDevice, settingId)
+ .onEach {
+ val existedPref =
+ dashboardFragment.preferenceScreen.findPreference<Preference>(
+ prefKey
+ )
+ val item =
+ it
+ ?: run {
+ existedPref?.let {
+ dashboardFragment.preferenceScreen.removePreference(
+ existedPref
+ )
+ }
+ return@onEach
+ }
+ buildPreference(existedPref, item, prefKey, settingItem.highlighted)
+ ?.apply {
+ key = prefKey
+ order = row
+ }
+ ?.also { dashboardFragment.preferenceScreen.addPreference(it) }
}
- .also { pref -> pref.setContent { buildPreference(layout, row, prefKey) } }
- fragment.preferenceScreen.addPreference(pref)
+ .launchIn(dashboardFragment.lifecycleScope)
+ }
}
}
- // TODO(b/343317785): figure out how to remove the foot preference.
- fragment.preferenceScreen.addPreference(ComposePreference(context).apply {
- order = 10000
- isEnabled = false
- isSelectable = false
- setContent { Spacer(modifier = Modifier.height(1.dp)) }
- })
for (row in items.indices) {
val settingItem = items[row]
val settingId = settingItem.settingId
- if (settingIdToXmlPreferences.containsKey(settingId)) {
- val pref = fragment.preferenceScreen.getPreference(row)
+ settingIdToXmlPreferences[settingId]?.let { pref ->
if (settingId == DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES) {
(getController(pref.key) as? BluetoothDetailsProfilesController)?.run {
- if (settingItem is DeviceSettingConfigItemModel.BuiltinItem.BluetoothProfilesItem) {
+ if (
+ settingItem
+ is DeviceSettingConfigItemModel.BuiltinItem.BluetoothProfilesItem
+ ) {
setInvisibleProfiles(settingItem.invisibleProfiles)
setHasExtraSpace(false)
}
}
}
- getController(pref.key)?.displayPreference(fragment.preferenceScreen)
+ getController(pref.key)?.displayPreference(dashboardFragment.preferenceScreen)
logItemShown(pref.key, pref.isVisible)
}
}
- fragment.lifecycleScope.launch {
+ dashboardFragment.lifecycleScope.launch {
if (isLoading) {
- fragment.setLoading(false, false)
+ dashboardFragment.setLoading(false, false)
isLoading = false
}
}
@@ -236,88 +247,171 @@
} ?: emit(null)
}
- private fun getDevicesSettingForRow(
- layout: DeviceSettingLayout,
- row: Int,
- ): Flow<List<DeviceSettingPreferenceModel>> =
- layout.rows[row].columns.flatMapLatest { columns ->
- if (columns.isEmpty()) {
- flowOf(emptyList())
- } else {
- combine(
- columns.map { column ->
- viewModel.getDeviceSetting(cachedDevice, column.settingId)
- }
- ) {
- it.toList().filterNotNull()
+ private fun buildPreference(
+ existedPref: Preference?,
+ model: DeviceSettingPreferenceModel,
+ prefKey: String,
+ highlighted: Boolean,
+ ): Preference? =
+ when (model) {
+ is DeviceSettingPreferenceModel.PlainPreference -> {
+ val pref =
+ existedPref
+ ?: run {
+ if (highlighted) SpotlightPreference(context) else Preference(context)
+ }
+ pref.apply {
+ title = model.title
+ summary = model.summary
+ icon = getDrawable(model.icon)
+ onPreferenceClickListener =
+ object : Preference.OnPreferenceClickListener {
+ override fun onPreferenceClick(p: Preference): Boolean {
+ logItemClick(prefKey, EVENT_CLICK_PRIMARY)
+ model.action?.let { triggerAction(it) }
+ return true
+ }
+ }
}
}
+ is DeviceSettingPreferenceModel.SwitchPreference ->
+ if (model.action == null) {
+ val pref =
+ existedPref as? SwitchPreferenceCompat ?: SwitchPreferenceCompat(context)
+ pref.apply {
+ title = model.title
+ summary = model.summary
+ icon = getDrawable(model.icon)
+ isChecked = model.checked
+ isEnabled = !model.disabled
+ onPreferenceChangeListener =
+ object : Preference.OnPreferenceChangeListener {
+ override fun onPreferenceChange(
+ p: Preference,
+ value: Any?,
+ ): Boolean {
+ (p as? TwoStatePreference)?.let { newState ->
+ val newState = value as? Boolean ?: return false
+ logItemClick(
+ prefKey,
+ if (newState) EVENT_SWITCH_ON else EVENT_SWITCH_OFF,
+ )
+ isEnabled = false
+ model.onCheckedChange.invoke(newState)
+ }
+ return false
+ }
+ }
+ }
+ } else {
+ val pref =
+ existedPref as? PrimarySwitchPreference ?: PrimarySwitchPreference(context)
+ pref.apply {
+ title = model.title
+ summary = model.summary
+ icon = getDrawable(model.icon)
+ isChecked = model.checked
+ isEnabled = !model.disabled
+ isSwitchEnabled = !model.disabled
+ onPreferenceClickListener =
+ object : Preference.OnPreferenceClickListener {
+ override fun onPreferenceClick(p: Preference): Boolean {
+ logItemClick(prefKey, EVENT_CLICK_PRIMARY)
+ triggerAction(model.action)
+ return true
+ }
+ }
+ onPreferenceChangeListener =
+ object : Preference.OnPreferenceChangeListener {
+ override fun onPreferenceChange(
+ p: Preference,
+ value: Any?,
+ ): Boolean {
+ val newState = value as? Boolean ?: return false
+ logItemClick(
+ prefKey,
+ if (newState) EVENT_SWITCH_ON else EVENT_SWITCH_OFF,
+ )
+ isSwitchEnabled = false
+ model.onCheckedChange.invoke(newState)
+ return false
+ }
+ }
+ }
+ }
+
+ is DeviceSettingPreferenceModel.MultiTogglePreference -> {
+ // TODO(b/399316980): implemented it by SegmentedButtonPreference
+ null
+ }
+ is DeviceSettingPreferenceModel.FooterPreference -> {
+ val pref = existedPref as? FooterPreference ?: FooterPreference(context)
+ pref.apply { title = model.footerText }
+ }
+ is DeviceSettingPreferenceModel.MoreSettingsPreference -> {
+ val pref = existedPref ?: Preference(context)
+ pref.apply {
+ title =
+ context.getString(R.string.bluetooth_device_more_settings_preference_title)
+ summary =
+ context.getString(
+ R.string.bluetooth_device_more_settings_preference_summary
+ )
+ icon = context.getDrawable(R.drawable.ic_chevron_right_24dp)
+ onPreferenceClickListener =
+ object : Preference.OnPreferenceClickListener {
+ override fun onPreferenceClick(p: Preference): Boolean {
+ logItemClick(prefKey, EVENT_CLICK_PRIMARY)
+ SubSettingLauncher(context)
+ .setDestination(
+ DeviceDetailsMoreSettingsFragment::class.java.name
+ )
+ .setSourceMetricsCategory(
+ dashboardFragment.getMetricsCategory()
+ )
+ .setArguments(
+ Bundle().apply {
+ putString(KEY_DEVICE_ADDRESS, cachedDevice.address)
+ }
+ )
+ .launch()
+ return true
+ }
+ }
+ }
+ }
+ is DeviceSettingPreferenceModel.HelpPreference -> {
+ null
+ }
}
- @Composable
- private fun buildPreference(layout: DeviceSettingLayout, row: Int, prefKey: String) {
- val contents by
- remember(row) { getDevicesSettingForRow(layout, row) }
- .collectAsStateWithLifecycle(initialValue = listOf())
-
- val highlighted by
- remember(row) {
- layout.rows[row].columns.map { columns -> columns.any { it.highlighted } }
+ private fun getDrawable(deviceSettingIcon: DeviceSettingIcon?): Drawable? =
+ when (deviceSettingIcon) {
+ is DeviceSettingIcon.BitmapIcon ->
+ deviceSettingIcon.bitmap.toDrawable(context.resources)
+ is DeviceSettingIcon.ResourceIcon -> context.getDrawable(deviceSettingIcon.resId)
+ null -> null
}
- .collectAsStateWithLifecycle(initialValue = false)
+
+ @Composable
+ private fun buildComposePreference(
+ cachedDevice: CachedBluetoothDevice,
+ settingId: Int,
+ prefKey: String,
+ ) {
+ val contents by
+ remember(settingId) { viewModel.getDeviceSetting(cachedDevice, settingId) }
+ .collectAsStateWithLifecycle(initialValue = null)
val settings = contents
- AnimatedVisibility(visible = settings.isNotEmpty(), enter = fadeIn(), exit = fadeOut()) {
- Box {
- Box(
- modifier =
- Modifier.matchParentSize()
- .padding(16.dp, 0.dp, 8.dp, 0.dp)
- .background(
- color =
- if (highlighted) {
- MaterialTheme.colorScheme.primaryContainer
- } else {
- Color.Transparent
- },
- shape = RoundedCornerShape(28.dp),
- )
- ) {}
- buildPreferences(settings, prefKey)
+ AnimatedVisibility(visible = settings != null, enter = fadeIn(), exit = fadeOut()) {
+ (settings as? DeviceSettingPreferenceModel.MultiTogglePreference)?.let {
+ buildMultiTogglePreference(it, prefKey)
}
}
}
@Composable
- fun buildPreferences(settings: List<DeviceSettingPreferenceModel?>, prefKey: String) {
- when (settings.size) {
- 0 -> {}
- 1 -> {
- when (val setting = settings[0]) {
- is DeviceSettingPreferenceModel.PlainPreference -> {
- buildPlainPreference(setting, prefKey)
- }
- is DeviceSettingPreferenceModel.SwitchPreference -> {
- buildSwitchPreference(setting, prefKey)
- }
- is DeviceSettingPreferenceModel.MultiTogglePreference -> {
- buildMultiTogglePreference(setting, prefKey)
- }
- is DeviceSettingPreferenceModel.FooterPreference -> {
- buildFooterPreference(setting)
- }
- is DeviceSettingPreferenceModel.MoreSettingsPreference -> {
- buildMoreSettingsPreference(prefKey)
- }
- is DeviceSettingPreferenceModel.HelpPreference -> {}
- null -> {}
- }
- }
- else -> {}
- }
- }
-
- @Composable
private fun buildMultiTogglePreference(
pref: DeviceSettingPreferenceModel.MultiTogglePreference,
prefKey: String,
@@ -332,107 +426,6 @@
)
}
- @Composable
- private fun buildSwitchPreference(
- model: DeviceSettingPreferenceModel.SwitchPreference,
- prefKey: String,
- ) {
- val switchPrefModel =
- object : SwitchPreferenceModel {
- override val title = model.title
- override val summary = { model.summary ?: "" }
- override val checked = { model.checked }
- override val onCheckedChange = { newState: Boolean ->
- logItemClick(prefKey, if (newState) EVENT_SWITCH_ON else EVENT_SWITCH_OFF)
- model.onCheckedChange(newState)
- }
- override val changeable = { !model.disabled }
- override val icon: (@Composable () -> Unit)?
- get() {
- if (model.icon == null) {
- return null
- }
- return { deviceSettingIcon(model.icon) }
- }
- }
- if (model.action != null) {
- TwoTargetSwitchPreference(
- switchPrefModel,
- primaryOnClick = {
- logItemClick(prefKey, EVENT_CLICK_PRIMARY)
- triggerAction(model.action)
- },
- primaryEnabled = { !model.disabled },
- )
- } else {
- SwitchPreference(switchPrefModel)
- }
- }
-
- @Composable
- private fun buildPlainPreference(
- model: DeviceSettingPreferenceModel.PlainPreference,
- prefKey: String,
- ) {
- SpaPreference(
- object : PreferenceModel {
- override val title = model.title
- override val summary = { model.summary ?: "" }
- override val onClick = {
- logItemClick(prefKey, EVENT_CLICK_PRIMARY)
- model.action?.let { triggerAction(it) }
- Unit
- }
- override val icon: (@Composable () -> Unit)?
- get() {
- if (model.icon == null) {
- return null
- }
- return { deviceSettingIcon(model.icon) }
- }
- }
- )
- }
-
- @Composable
- fun buildMoreSettingsPreference(prefKey: String) {
- SpaPreference(
- object : PreferenceModel {
- override val title =
- stringResource(R.string.bluetooth_device_more_settings_preference_title)
- override val summary = {
- context.getString(R.string.bluetooth_device_more_settings_preference_summary)
- }
- override val onClick = {
- logItemClick(prefKey, EVENT_CLICK_PRIMARY)
- SubSettingLauncher(context)
- .setDestination(DeviceDetailsMoreSettingsFragment::class.java.name)
- .setSourceMetricsCategory(fragment.getMetricsCategory())
- .setArguments(
- Bundle().apply { putString(KEY_DEVICE_ADDRESS, cachedDevice.address) }
- )
- .launch()
- }
- override val icon =
- @Composable {
- deviceSettingIcon(
- DeviceSettingIcon.ResourceIcon(R.drawable.ic_chevron_right_24dp)
- )
- }
- }
- )
- }
-
- @Composable
- fun buildFooterPreference(model: DeviceSettingPreferenceModel.FooterPreference) {
- Footer(footerText = model.footerText)
- }
-
- @Composable
- private fun deviceSettingIcon(icon: DeviceSettingIcon?) {
- icon?.let { Icon(it, modifier = Modifier.size(SettingsDimension.itemIconSize)) }
- }
-
private fun logItemClick(preferenceKey: String, value: Int = 0) {
logAction(preferenceKey, SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_CLICKED, value)
}
@@ -452,7 +445,7 @@
if (it) EVENT_VISIBLE else EVENT_INVISIBLE,
)
}
- .launchIn(fragment.lifecycleScope)
+ .launchIn(dashboardFragment.lifecycleScope)
}
}
.value = visible
@@ -485,7 +478,7 @@
private fun disableController(controller: AbstractPreferenceController) {
if (controller is LifecycleObserver) {
- fragment.settingsLifecycle.removeObserver(controller as LifecycleObserver)
+ dashboardFragment.settingsLifecycle.removeObserver(controller as LifecycleObserver)
}
if (controller is BlockingPrefWithSliceController) {
@@ -504,6 +497,19 @@
private fun getPreferenceKey(settingId: Int) = "DEVICE_SETTING_${settingId}"
+ private class SpotlightPreference(context: Context) : Preference(context) {
+
+ init {
+ layoutResource = R.layout.bluetooth_device_spotlight_preference
+ }
+
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+ holder.isDividerAllowedBelow = false
+ holder.isDividerAllowedAbove = false
+ }
+ }
+
private companion object {
const val TAG = "DeviceDetailsFormatter"
const val EVENT_SWITCH_OFF = 0
diff --git a/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt b/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
index 8d3b853..5434ec9 100644
--- a/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
+++ b/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModel.kt
@@ -23,9 +23,6 @@
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.android.settings.R
-import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
-import com.android.settings.bluetooth.ui.layout.DeviceSettingLayoutColumn
-import com.android.settings.bluetooth.ui.layout.DeviceSettingLayoutRow
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
@@ -39,11 +36,8 @@
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
class BluetoothDeviceDetailsViewModel(
private val application: Application,
@@ -141,43 +135,6 @@
}
}
- suspend fun getLayout(fragment: FragmentTypeModel): DeviceSettingLayout? {
- val configItems = getItems(fragment) ?: return null
- val idToDeviceSetting =
- configItems
- .filterIsInstance<DeviceSettingConfigItemModel.AppProvidedItem>()
- .associateBy({ it.settingId }, { getDeviceSetting(cachedDevice, it.settingId) })
-
- val configDeviceSetting =
- configItems.map { idToDeviceSetting[it.settingId] ?: flowOf(null) }
- val positionToSettingIds =
- combine(configDeviceSetting) { settings ->
- val positionMapping = mutableMapOf<Int, List<DeviceSettingLayoutColumn>>()
- for (i in settings.indices) {
- val configItem = configItems[i]
- val setting = settings[i]
- val isXmlPreference = configItem is DeviceSettingConfigItemModel.BuiltinItem
- if (!isXmlPreference && setting == null) {
- continue
- }
- positionMapping[i] =
- listOf(
- DeviceSettingLayoutColumn(
- configItem.settingId,
- configItem.highlighted,
- )
- )
- }
- positionMapping
- }
- .stateIn(viewModelScope, SharingStarted.WhileSubscribed(), initialValue = mapOf())
- return DeviceSettingLayout(
- configItems.indices.map { idx ->
- DeviceSettingLayoutRow(positionToSettingIds.map { it[idx] ?: emptyList() })
- }
- )
- }
-
class Factory(
private val application: Application,
private val bluetoothAdapter: BluetoothAdapter,
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java
index 90ff344..c3459f5 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDisconnectDialogFragment.java
@@ -103,7 +103,7 @@
return false;
}
Lifecycle.State currentState = host.getLifecycle().getCurrentState();
- if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+ if (!currentState.isAtLeast(Lifecycle.State.CREATED)) {
Log.d(TAG, "Fail to show dialog with state: " + currentState);
return false;
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java
index 02c4a4c..f244f5f 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingJoinDialogFragment.java
@@ -102,7 +102,7 @@
return false;
}
Lifecycle.State currentState = host.getLifecycle().getCurrentState();
- if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+ if (!currentState.isAtLeast(Lifecycle.State.CREATED)) {
Log.d(TAG, "Fail to show dialog with state: " + currentState);
return false;
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
index 65a9ac3..8a11ac5 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingStopDialogFragment.java
@@ -100,7 +100,7 @@
return false;
}
Lifecycle.State currentState = host.getLifecycle().getCurrentState();
- if (!currentState.isAtLeast(Lifecycle.State.STARTED)) {
+ if (!currentState.isAtLeast(Lifecycle.State.CREATED)) {
Log.d(TAG, "Fail to show dialog with state: " + currentState);
return false;
}
diff --git a/src/com/android/settings/development/Enable16kPagesPreferenceController.java b/src/com/android/settings/development/Enable16kPagesPreferenceController.java
index d8ad55f..1c1b713 100644
--- a/src/com/android/settings/development/Enable16kPagesPreferenceController.java
+++ b/src/com/android/settings/development/Enable16kPagesPreferenceController.java
@@ -186,7 +186,13 @@
public void onFailure(@NonNull Throwable t) {
hideProgressDialog();
Log.e(TAG, "Failed to call applyPayload of UpdateEngineStable!", t);
- displayToast(mContext.getString(R.string.toast_16k_update_failed_text));
+ // installUpdate will always throw localized messages.
+ String message = t.getMessage();
+ if (message != null) {
+ displayToast(message);
+ } else {
+ displayToast(mContext.getString(R.string.toast_16k_update_failed_text));
+ }
}
},
ContextCompat.getMainExecutor(mContext));
@@ -208,10 +214,8 @@
int status = data.getInt(SystemUpdateManager.KEY_STATUS);
if (status != SystemUpdateManager.STATUS_UNKNOWN
&& status != SystemUpdateManager.STATUS_IDLE) {
- throw new RuntimeException(
- "System has pending update! Please restart the device to complete applying"
- + " pending update. If you are seeing this after using 16KB developer"
- + " options, please check configuration and OTA packages!");
+ Log.e(TAG, "SystemUpdateManager is not available. Status :" + status);
+ throw new RuntimeException(mContext.getString(R.string.error_pending_updates));
}
// Publish system update info
@@ -223,7 +227,11 @@
Log.i(TAG, "Update file path is " + updateFile.getAbsolutePath());
applyUpdateFile(updateFile);
} catch (IOException e) {
- throw new RuntimeException(e);
+ Log.e(TAG, "Error occurred while applying OTA ", e);
+ throw new RuntimeException(mContext.getString(R.string.error_ota_failed));
+ } catch (Exception e) {
+ Log.e(TAG, "Unknown error occurred while applying OTA ", e);
+ throw new RuntimeException(mContext.getString(R.string.toast_16k_update_failed_text));
}
}
diff --git a/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java b/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
index 0835081..93d3a0b 100644
--- a/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
+++ b/src/com/android/settings/development/linuxterminal/LinuxTerminalPreferenceController.java
@@ -44,7 +44,7 @@
static final long MEMORY_MIN_BYTES = DataUnit.GIGABYTES.toBytes(4); // 4_000_000_000
@VisibleForTesting
- static final long STORAGE_MIN_BYTES = DataUnit.GIGABYTES.toBytes(64); // 64_000_000_000
+ static final long STORAGE_MIN_BYTES = DataUnit.GIGABYTES.toBytes(16); // 16_000_000_000
private static final String LINUX_TERMINAL_KEY = "linux_terminal";
diff --git a/src/com/android/settings/display/AdaptiveSleepPreference.kt b/src/com/android/settings/display/AdaptiveSleepPreference.kt
index a38925c..32f805f 100644
--- a/src/com/android/settings/display/AdaptiveSleepPreference.kt
+++ b/src/com/android/settings/display/AdaptiveSleepPreference.kt
@@ -33,9 +33,8 @@
import com.android.settings.restriction.PreferenceRestrictionMixin
import com.android.settingslib.RestrictedSwitchPreference
import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.KeyValueStoreDelegate
import com.android.settingslib.datastore.SettingsSecureStore
-import com.android.settingslib.datastore.SettingsStore
import com.android.settingslib.metadata.BooleanValuePreference
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceLifecycleContext
@@ -106,16 +105,14 @@
@Suppress("UNCHECKED_CAST")
private class Storage(
private val context: Context,
- private val settingsStore: SettingsStore = SettingsSecureStore.get(context),
- ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+ private val settingsStore: KeyValueStore = SettingsSecureStore.get(context),
+ ) : KeyValueStoreDelegate {
- override fun contains(key: String) = settingsStore.contains(key)
+ override val keyValueStoreDelegate
+ get() = settingsStore
override fun <T : Any> getValue(key: String, valueType: Class<T>) =
(context.canBeEnabled() && settingsStore.getBoolean(key) == true) as T
-
- override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) =
- settingsStore.setBoolean(key, value as Boolean?)
}
override fun onStart(context: PreferenceLifecycleContext) {
diff --git a/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt b/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt
index 2ce6436..26d1c94 100644
--- a/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt
+++ b/src/com/android/settings/display/BatteryPercentageSwitchPreference.kt
@@ -23,8 +23,7 @@
import com.android.settings.contract.KEY_BATTERY_PERCENTAGE
import com.android.settings.metrics.PreferenceActionMetricsProvider
import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
-import com.android.settingslib.datastore.SettingsStore
+import com.android.settingslib.datastore.KeyValueStoreDelegate
import com.android.settingslib.datastore.SettingsSystemStore
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.ReadWritePermit
@@ -71,17 +70,11 @@
@Suppress("UNCHECKED_CAST")
private class BatteryPercentageStorage(
private val context: Context,
- private val settingsStore: SettingsStore,
- ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+ private val settingsStore: KeyValueStore,
+ ) : KeyValueStoreDelegate {
- override fun contains(key: String) = settingsStore.contains(KEY)
-
- override fun <T : Any> getValue(key: String, valueType: Class<T>) =
- (settingsStore.getBoolean(key) ?: getDefaultValue(key, valueType)) as T
-
- override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
- settingsStore.setBoolean(key, value as Boolean)
- }
+ override val keyValueStoreDelegate
+ get() = settingsStore
override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
context.resources.getBoolean(
diff --git a/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java b/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java
index e38f5d4..d3950ee 100644
--- a/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java
+++ b/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java
@@ -34,6 +34,7 @@
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
import com.android.settingslib.search.SearchIndexableRaw;
@@ -47,8 +48,8 @@
private final DeviceStateRotationLockSettingsManager mAutoRotateSettingsManager;
private final int mOrder;
- private final DeviceStateRotationLockSettingsManager.DeviceStateRotationLockSettingsListener
- mDeviceStateRotationLockSettingsListener = () -> updateState(mPreference);
+ private final DeviceStateAutoRotateSettingManager.DeviceStateAutoRotateSettingListener
+ mDeviceStateAutoRotateSettingListener = () -> updateState(mPreference);
private final int mDeviceState;
private final String mDeviceStateDescription;
private final MetricsFeatureProvider mMetricsFeatureProvider;
@@ -77,12 +78,12 @@
@OnLifecycleEvent(ON_START)
void onStart() {
- mAutoRotateSettingsManager.registerListener(mDeviceStateRotationLockSettingsListener);
+ mAutoRotateSettingsManager.registerListener(mDeviceStateAutoRotateSettingListener);
}
@OnLifecycleEvent(ON_STOP)
void onStop() {
- mAutoRotateSettingsManager.unregisterListener(mDeviceStateRotationLockSettingsListener);
+ mAutoRotateSettingsManager.unregisterListener(mDeviceStateAutoRotateSettingListener);
}
@Override
diff --git a/src/com/android/settings/display/DeviceStateAutoRotationHelper.java b/src/com/android/settings/display/DeviceStateAutoRotationHelper.java
index 223ef1a..3bf9def 100644
--- a/src/com/android/settings/display/DeviceStateAutoRotationHelper.java
+++ b/src/com/android/settings/display/DeviceStateAutoRotationHelper.java
@@ -26,7 +26,7 @@
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
-import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager.SettableDeviceState;
+import com.android.settingslib.devicestate.SettableDeviceState;
import com.android.settingslib.search.SearchIndexableRaw;
import com.google.common.collect.ImmutableList;
diff --git a/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt b/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt
index ee538db..8f1f9b5 100644
--- a/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt
+++ b/src/com/android/settings/display/PeakRefreshRateSwitchPreference.kt
@@ -29,8 +29,7 @@
import com.android.settings.metrics.PreferenceActionMetricsProvider
import com.android.settingslib.datastore.HandlerExecutor
import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
-import com.android.settingslib.datastore.SettingsStore
+import com.android.settingslib.datastore.KeyValueStoreDelegate
import com.android.settingslib.datastore.SettingsSystemStore
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceLifecycleContext
@@ -112,18 +111,16 @@
@Suppress("UNCHECKED_CAST")
private class PeakRefreshRateStore(
private val context: Context,
- private val settingsStore: SettingsStore,
- ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+ private val settingsStore: KeyValueStore,
+ ) : KeyValueStoreDelegate {
- override fun contains(key: String) = settingsStore.contains(key)
+ override val keyValueStoreDelegate
+ get() = settingsStore
- override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>): T? {
- if (key != KEY) return super.getDefaultValue(key, valueType)
- return context.defaultPeakRefreshRate.refreshRateAsBoolean(context) as T
- }
+ override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
+ context.defaultPeakRefreshRate.refreshRateAsBoolean(context) as T
override fun <T : Any> getValue(key: String, valueType: Class<T>): T? {
- if (key != KEY) return null
val refreshRate = settingsStore.getFloat(KEY) ?: context.defaultPeakRefreshRate
return refreshRate.refreshRateAsBoolean(context) as T
}
diff --git a/src/com/android/settings/display/SmartAutoRotateController.java b/src/com/android/settings/display/SmartAutoRotateController.java
index b5e3af2..c99b2f8 100644
--- a/src/com/android/settings/display/SmartAutoRotateController.java
+++ b/src/com/android/settings/display/SmartAutoRotateController.java
@@ -46,6 +46,7 @@
import com.android.settings.core.TogglePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager;
import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager;
/**
@@ -75,8 +76,8 @@
};
private final DeviceStateRotationLockSettingsManager mDeviceStateAutoRotateSettingsManager;
- private final DeviceStateRotationLockSettingsManager.DeviceStateRotationLockSettingsListener
- mDeviceStateRotationLockSettingsListener = () -> updateState(mPreference);
+ private final DeviceStateAutoRotateSettingManager.DeviceStateAutoRotateSettingListener
+ mDeviceStateAutoRotateSettingListener = () -> updateState(mPreference);
private RotationPolicy.RotationPolicyListener mRotationPolicyListener;
public SmartAutoRotateController(Context context, String preferenceKey) {
@@ -140,7 +141,7 @@
}
RotationPolicy.registerRotationPolicyListener(mContext, mRotationPolicyListener);
mDeviceStateAutoRotateSettingsManager.registerListener(
- mDeviceStateRotationLockSettingsListener);
+ mDeviceStateAutoRotateSettingListener);
mPrivacyManager.addSensorPrivacyListener(CAMERA, mPrivacyChangedListener);
}
@@ -152,7 +153,7 @@
mRotationPolicyListener = null;
}
mDeviceStateAutoRotateSettingsManager.unregisterListener(
- mDeviceStateRotationLockSettingsListener);
+ mDeviceStateAutoRotateSettingListener);
mPrivacyManager.removeSensorPrivacyListener(CAMERA, mPrivacyChangedListener);
}
diff --git a/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt b/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt
index 80f1d00..d495967 100644
--- a/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt
+++ b/src/com/android/settings/network/AdaptiveConnectivityTogglePreference.kt
@@ -24,9 +24,8 @@
import com.android.settings.contract.KEY_ADAPTIVE_CONNECTIVITY
import com.android.settings.metrics.PreferenceActionMetricsProvider
import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.KeyValueStoreDelegate
import com.android.settingslib.datastore.SettingsSecureStore
-import com.android.settingslib.datastore.SettingsStore
import com.android.settingslib.metadata.MainSwitchPreference
import com.android.settingslib.metadata.ReadWritePermit
import com.android.settingslib.metadata.SensitivityLevel
@@ -42,7 +41,7 @@
override fun tags(context: Context) = arrayOf(KEY_ADAPTIVE_CONNECTIVITY)
override fun storage(context: Context): KeyValueStore =
- AdaptiveConnectivityToggleStorage(context, SettingsSecureStore.get(context))
+ AdaptiveConnectivityToggleStorage(context)
override fun getReadPermissions(context: Context) = SettingsSecureStore.getReadPermissions()
@@ -64,20 +63,20 @@
@Suppress("UNCHECKED_CAST")
private class AdaptiveConnectivityToggleStorage(
private val context: Context,
- private val settingsStore: SettingsStore,
- ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+ private val settingsStore: KeyValueStore = SettingsSecureStore.get(context),
+ ) : KeyValueStoreDelegate {
- override fun contains(key: String) = settingsStore.contains(KEY)
+ override val keyValueStoreDelegate
+ get() = settingsStore
override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
DEFAULT_VALUE as T
- override fun <T : Any> getValue(key: String, valueType: Class<T>) =
- (settingsStore.getBoolean(key) ?: DEFAULT_VALUE) as T
-
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
- settingsStore.setBoolean(key, value as Boolean)
- context.getSystemService(WifiManager::class.java)?.setWifiScoringEnabled(value)
+ settingsStore.setValue(key, valueType, value)
+ context
+ .getSystemService(WifiManager::class.java)
+ ?.setWifiScoringEnabled((value as Boolean?) ?: DEFAULT_VALUE)
}
}
diff --git a/src/com/android/settings/network/AirplaneModePreference.kt b/src/com/android/settings/network/AirplaneModePreference.kt
index de2eb1a..5a0dd5a 100644
--- a/src/com/android/settings/network/AirplaneModePreference.kt
+++ b/src/com/android/settings/network/AirplaneModePreference.kt
@@ -36,9 +36,8 @@
import com.android.settings.restriction.PreferenceRestrictionMixin
import com.android.settingslib.RestrictedSwitchPreference
import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.KeyValueStoreDelegate
import com.android.settingslib.datastore.SettingsGlobalStore
-import com.android.settingslib.datastore.SettingsStore
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.PreferenceLifecycleContext
import com.android.settingslib.metadata.PreferenceLifecycleProvider
@@ -92,17 +91,15 @@
@Suppress("UNCHECKED_CAST")
private class AirplaneModeStorage(
private val context: Context,
- private val settingsStore: SettingsStore = SettingsGlobalStore.get(context),
- ) : KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
+ private val settingsStore: KeyValueStore = SettingsGlobalStore.get(context),
+ ) : KeyValueStoreDelegate {
- override fun contains(key: String) = settingsStore.contains(KEY)
+ override val keyValueStoreDelegate
+ get() = settingsStore
override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) =
DEFAULT_VALUE as T
- override fun <T : Any> getValue(key: String, valueType: Class<T>): T =
- (settingsStore.getBoolean(key) ?: DEFAULT_VALUE) as T
-
override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) {
settingsStore.setValue(key, valueType, value)
diff --git a/src/com/android/settings/privatespace/PrivateSpaceEducation.java b/src/com/android/settings/privatespace/PrivateSpaceEducation.java
index dfaf8b9..093d7a5 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceEducation.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceEducation.java
@@ -44,6 +44,8 @@
public class PrivateSpaceEducation extends InstrumentedFragment {
private static final String TAG = "PrivateSpaceEducation";
+ private boolean mIsAnimationPlaying = true;
+
@Override
public View onCreateView(
LayoutInflater inflater,
@@ -73,6 +75,7 @@
.build());
LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation);
LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView);
+ lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView));
TextView infoTextView = rootView.findViewById(R.id.learn_more);
Pattern pattern = Pattern.compile(infoTextView.getText().toString());
@@ -110,4 +113,13 @@
}
};
}
+
+ private void handleAnimationClick(LottieAnimationView lottieAnimationView) {
+ if (mIsAnimationPlaying) {
+ lottieAnimationView.pauseAnimation();
+ } else {
+ lottieAnimationView.playAnimation();
+ }
+ mIsAnimationPlaying = !mIsAnimationPlaying;
+ }
}
diff --git a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java
index 28ac97f..47cf3ba 100644
--- a/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java
+++ b/src/com/android/settings/privatespace/PrivateSpaceSetLockFragment.java
@@ -51,6 +51,8 @@
private static final String TAG = "PrivateSpaceSetLockFrag";
private static final int HEADER_TEXT_MAX_LINES = 4;
+ private boolean mIsAnimationPlaying = true;
+
@Override
public View onCreateView(
LayoutInflater inflater,
@@ -91,6 +93,7 @@
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation);
LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView);
+ lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView));
return rootView;
}
@@ -130,4 +133,13 @@
Log.w(TAG, "Private profile user handle is null");
}
}
+
+ private void handleAnimationClick(LottieAnimationView lottieAnimationView) {
+ if (mIsAnimationPlaying) {
+ lottieAnimationView.pauseAnimation();
+ } else {
+ lottieAnimationView.playAnimation();
+ }
+ mIsAnimationPlaying = !mIsAnimationPlaying;
+ }
}
diff --git a/src/com/android/settings/privatespace/SetupSuccessFragment.java b/src/com/android/settings/privatespace/SetupSuccessFragment.java
index bfd9e96..538912e 100644
--- a/src/com/android/settings/privatespace/SetupSuccessFragment.java
+++ b/src/com/android/settings/privatespace/SetupSuccessFragment.java
@@ -49,6 +49,8 @@
public class SetupSuccessFragment extends InstrumentedFragment {
private static final String TAG = "SetupSuccessFragment";
+ private boolean mIsAnimationPlaying = true;
+
@Override
public View onCreateView(
LayoutInflater inflater,
@@ -80,6 +82,7 @@
requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);
LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation);
LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView);
+ lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView));
return rootView;
}
@@ -141,4 +144,13 @@
task.finishAndRemoveTask();
}
}
+
+ private void handleAnimationClick(LottieAnimationView lottieAnimationView) {
+ if (mIsAnimationPlaying) {
+ lottieAnimationView.pauseAnimation();
+ } else {
+ lottieAnimationView.playAnimation();
+ }
+ mIsAnimationPlaying = !mIsAnimationPlaying;
+ }
}
diff --git a/src/com/android/settings/sound/MediaControlsLockscreenSwitchPreference.kt b/src/com/android/settings/sound/MediaControlsLockscreenSwitchPreference.kt
index 59c1b8f..2d70b83 100644
--- a/src/com/android/settings/sound/MediaControlsLockscreenSwitchPreference.kt
+++ b/src/com/android/settings/sound/MediaControlsLockscreenSwitchPreference.kt
@@ -18,22 +18,21 @@
import android.content.Context
import android.provider.Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN
-
+import com.android.settings.R
import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.KeyValueStoreDelegate
import com.android.settingslib.datastore.SettingsSecureStore
-import com.android.settingslib.datastore.SettingsStore
import com.android.settingslib.metadata.ReadWritePermit
import com.android.settingslib.metadata.SensitivityLevel
import com.android.settingslib.metadata.SwitchPreference
-import com.android.settings.R
// LINT.IfChange
-class MediaControlsLockscreenSwitchPreference : SwitchPreference(
- KEY,
- R.string.media_controls_lockscreen_title,
- R.string.media_controls_lockscreen_description,
-) {
+class MediaControlsLockscreenSwitchPreference :
+ SwitchPreference(
+ KEY,
+ R.string.media_controls_lockscreen_title,
+ R.string.media_controls_lockscreen_description,
+ ) {
override val sensitivityLevel
get() = SensitivityLevel.NO_SENSITIVITY
@@ -52,21 +51,17 @@
MediaControlsLockscreenStore(SettingsSecureStore.get(context))
@Suppress("UNCHECKED_CAST")
- private class MediaControlsLockscreenStore(private val settingsStore: SettingsStore) :
- KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
- override fun contains(key: String) = settingsStore.contains(key)
+ private class MediaControlsLockscreenStore(private val settingsStore: KeyValueStore) :
+ KeyValueStoreDelegate {
+
+ override val keyValueStoreDelegate
+ get() = settingsStore
override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) = true as T
-
- override fun <T : Any> getValue(key: String, valueType: Class<T>) =
- settingsStore.getValue(key, valueType) ?: getDefaultValue(key, valueType)
-
- override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) =
- settingsStore.setValue(key, valueType, value)
}
companion object {
const val KEY = MEDIA_CONTROLS_LOCK_SCREEN
}
}
-// LINT.ThenChange(MediaControlsLockScreenPreferenceController.java)
\ No newline at end of file
+// LINT.ThenChange(MediaControlsLockScreenPreferenceController.java)
diff --git a/src/com/android/settings/sound/MediaControlsScreen.kt b/src/com/android/settings/sound/MediaControlsScreen.kt
index d63259c..f9c2f64 100644
--- a/src/com/android/settings/sound/MediaControlsScreen.kt
+++ b/src/com/android/settings/sound/MediaControlsScreen.kt
@@ -17,21 +17,18 @@
package com.android.settings.sound
import android.content.Context
-
import com.android.settings.R
import com.android.settings.flags.Flags
import com.android.settingslib.datastore.AbstractKeyedDataObservable
import com.android.settingslib.datastore.HandlerExecutor
-import com.android.settingslib.datastore.KeyedObserver
import com.android.settingslib.datastore.KeyValueStore
-import com.android.settingslib.datastore.KeyedObservableDelegate
+import com.android.settingslib.datastore.KeyValueStoreDelegate
+import com.android.settingslib.datastore.KeyedObserver
import com.android.settingslib.datastore.SettingsSecureStore
-import com.android.settingslib.datastore.SettingsStore
import com.android.settingslib.metadata.PreferenceChangeReason
-import com.android.settingslib.metadata.ProvidePreferenceScreen
import com.android.settingslib.metadata.PreferenceSummaryProvider
+import com.android.settingslib.metadata.ProvidePreferenceScreen
import com.android.settingslib.metadata.preferenceHierarchy
-
import com.android.settingslib.preference.PreferenceScreenCreator
// LINT.IfChange
@@ -83,21 +80,16 @@
}
@Suppress("UNCHECKED_CAST")
- class MediaControlsStore(private val settingsStore: SettingsStore) :
- KeyedObservableDelegate<String>(settingsStore), KeyValueStore {
- override fun contains(key: String) = settingsStore.contains(key)
+ class MediaControlsStore(private val settingsStore: KeyValueStore) : KeyValueStoreDelegate {
+
+ override val keyValueStoreDelegate
+ get() = settingsStore
override fun <T : Any> getDefaultValue(key: String, valueType: Class<T>) = true as T
-
- override fun <T : Any> getValue(key: String, valueType: Class<T>) =
- settingsStore.getValue(key, valueType) ?: getDefaultValue(key, valueType)
-
- override fun <T : Any> setValue(key: String, valueType: Class<T>, value: T?) =
- settingsStore.setValue(key, valueType, value)
}
companion object {
const val KEY = "media_controls"
}
}
-// LINT.ThenChange(MediaControlsSettings.java)
\ No newline at end of file
+// LINT.ThenChange(MediaControlsSettings.java)
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
index 1e6e545..cbd9c53 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreference.kt
@@ -45,7 +45,7 @@
initialValue = stringResource(R.string.summary_placeholder),
)
Preference(object : PreferenceModel {
- override val title = stringResource(R.string.aspect_ratio_experimental_title)
+ override val title = stringResource(R.string.aspect_ratio_title)
override val summary = { summary }
override val onClick = presenter::startActivity
})
diff --git a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
index 3241d71..5902677 100644
--- a/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
+++ b/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProvider.kt
@@ -85,7 +85,7 @@
fun EntryItem() {
val summary = getSummary()
Preference(object : PreferenceModel {
- override val title = stringResource(R.string.aspect_ratio_experimental_title)
+ override val title = stringResource(R.string.aspect_ratio_title)
override val summary = { summary }
override val onClick = navigator(name)
})
@@ -108,7 +108,7 @@
= { AppList() },
) {
AppListPage(
- title = stringResource(R.string.aspect_ratio_experimental_title),
+ title = stringResource(R.string.aspect_ratio_title),
listModel = rememberContext(::UserAspectRatioAppListModel),
appList = appList,
header = {
diff --git a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
index 6710da9..a077e47 100644
--- a/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/AccessibilitySettingsTest.java
@@ -21,10 +21,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.robolectric.Shadows.shadowOf;
@@ -46,8 +43,6 @@
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
-import android.view.Menu;
-import android.view.MenuItem;
import android.view.accessibility.AccessibilityManager;
import androidx.fragment.app.Fragment;
@@ -112,7 +107,6 @@
private static final String EMPTY_STRING = "";
private static final String DEFAULT_SUMMARY = "default summary";
private static final String DEFAULT_DESCRIPTION = "default description";
- private static final String DEFAULT_CATEGORY = "default category";
private static final String DEFAULT_LABEL = "default label";
private static final Boolean SERVICE_ENABLED = true;
private static final Boolean SERVICE_DISABLED = false;
@@ -128,10 +122,6 @@
private ShadowAccessibilityManager mShadowAccessibilityManager;
@Mock
private LocalBluetoothManager mLocalBluetoothManager;
- @Mock
- private Menu mMenu;
- @Mock
- private MenuItem mMenuItem;
private ActivityController<SettingsActivity> mActivityController;
@@ -452,58 +442,6 @@
}
@Test
- @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
- public void onCreateOptionsMenu_enableLowVisionGenericFeedback_shouldAddSendFeedbackMenu() {
- setupFragment();
- mFragment.setFeedbackManager(
- new FeedbackManager(mFragment.getActivity(), PACKAGE_NAME, DEFAULT_CATEGORY));
-
- mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null);
-
- verify(mMenu).add(anyInt(), anyInt(), anyInt(), anyInt());
- }
-
- @Test
- @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
- public void onCreateOptionsMenu_disableLowVisionGenericFeedback_shouldNotAddSendFeedbackMenu() {
- setupFragment();
- mFragment.setFeedbackManager(
- new FeedbackManager(mFragment.getActivity(), PACKAGE_NAME, DEFAULT_CATEGORY));
-
- mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null);
-
- verify(mMenu, never()).add(anyInt(), anyInt(), anyInt(), anyInt());
- }
-
- @Test
- @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
- public void onOptionsItemSelected_enableLowVisionGenericFeedback_shouldStartSendFeedback() {
- setupFragment();
- mFragment.setFeedbackManager(
- new FeedbackManager(mFragment.getActivity(), PACKAGE_NAME, DEFAULT_CATEGORY));
- when(mMenuItem.getItemId()).thenReturn(AccessibilitySettings.MENU_ID_SEND_FEEDBACK);
-
- mFragment.onOptionsItemSelected(mMenuItem);
-
- Intent startedIntent = shadowOf(mFragment.getActivity()).getNextStartedActivity();
- assertThat(startedIntent).isNotNull();
- }
-
- @Test
- @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
- public void onOptionsItemSelected_disableLowVisionGenericFeedback_shouldNotStartSendFeedback() {
- setupFragment();
- mFragment.setFeedbackManager(
- new FeedbackManager(mFragment.getActivity(), PACKAGE_NAME, DEFAULT_CATEGORY));
- when(mMenuItem.getItemId()).thenReturn(AccessibilitySettings.MENU_ID_SEND_FEEDBACK);
-
- mFragment.onOptionsItemSelected(mMenuItem);
-
- Intent startedIntent = shadowOf(mFragment.getActivity()).getNextStartedActivity();
- assertThat(startedIntent).isNull();
- }
-
- @Test
public void testAccessibilityMenuInSystem_IncludedInInteractionControl() {
mShadowAccessibilityManager.setInstalledAccessibilityServiceList(
List.of(getMockAccessibilityServiceInfo(
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java
index ff73e7f..9d304ba 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleColorInversionPreferenceFragmentTest.java
@@ -31,6 +31,7 @@
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
+import android.content.res.Resources;
import android.os.Bundle;
import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
@@ -82,6 +83,8 @@
private PreferenceManager mPreferenceManager;
@Mock
private FragmentActivity mActivity;
+ @Mock
+ private Resources mResources;
@Before
public void setUpTestFragment() {
@@ -93,6 +96,7 @@
when(mFragment.getContext()).thenReturn(mContext);
when(mFragment.getActivity()).thenReturn(mActivity);
when(mActivity.getContentResolver()).thenReturn(mContext.getContentResolver());
+ when(mActivity.getResources()).thenReturn(mResources);
mScreen = spy(new PreferenceScreen(mContext, /* attrs= */ null));
when(mScreen.findPreference(mFragment.getUseServicePreferenceKey()))
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
index f72b591..cdd309f 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleFeaturePreferenceFragmentTest.java
@@ -23,8 +23,6 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -38,16 +36,14 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.icu.text.CaseMap;
import android.net.Uri;
import android.os.Bundle;
-import android.platform.test.annotations.DisableFlags;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import android.provider.Settings;
import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityManager;
@@ -107,19 +103,10 @@
PLACEHOLDER_PACKAGE_NAME + "tile.placeholder";
private static final ComponentName PLACEHOLDER_TILE_COMPONENT_NAME = new ComponentName(
PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_TILE_CLASS_NAME);
- private static final String PLACEHOLDER_TILE_TOOLTIP_CONTENT =
- PLACEHOLDER_PACKAGE_NAME + "tooltip_content";
- private static final String PLACEHOLDER_CATEGORY = "category";
- private static final String PLACEHOLDER_DIALOG_TITLE = "title";
private static final String DEFAULT_SUMMARY = "default summary";
private static final String DEFAULT_DESCRIPTION = "default description";
private static final String DEFAULT_TOP_INTRO = "default top intro";
- private static final String SOFTWARE_SHORTCUT_KEY =
- Settings.Secure.ACCESSIBILITY_BUTTON_TARGETS;
- private static final String HARDWARE_SHORTCUT_KEY =
- Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
-
private TestToggleFeaturePreferenceFragment mFragment;
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
@@ -135,9 +122,7 @@
@Mock
private PackageManager mPackageManager;
@Mock
- private Menu mMenu;
- @Mock
- private MenuItem mMenuItem;
+ private Resources mResources;
@Before
public void setUpTestFragment() {
@@ -150,6 +135,7 @@
when(mFragment.getContext()).thenReturn(mContext);
when(mFragment.getActivity()).thenReturn(mActivity);
when(mActivity.getContentResolver()).thenReturn(mContentResolver);
+ when(mActivity.getResources()).thenReturn(mResources);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
final PreferenceScreen screen = spy(new PreferenceScreen(mContext, null));
when(screen.getPreferenceManager()).thenReturn(mPreferenceManager);
@@ -187,61 +173,6 @@
}
@Test
- @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
- public void onCreateOptionsMenu_enableLowVisionGenericFeedback_shouldAddSendFeedbackMenu() {
- mFragment.setFeedbackManager(
- new FeedbackManager(mActivity, PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CATEGORY));
-
- mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null);
-
- verify(mMenu).add(anyInt(), eq(ToggleFeaturePreferenceFragment.MENU_ID_SEND_FEEDBACK),
- anyInt(), eq(R.string.accessibility_send_feedback_title));
- }
-
- @Test
- @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
- public void onCreateOptionsMenu_disableLowVisionGenericFeedback_shouldNotAddSendFeedbackMenu() {
- mFragment.setFeedbackManager(
- new FeedbackManager(mActivity, PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CATEGORY));
-
- mFragment.onCreateOptionsMenu(mMenu, /* inflater= */ null);
-
- verify(mMenu, never()).add(anyInt(),
- eq(ToggleFeaturePreferenceFragment.MENU_ID_SEND_FEEDBACK), anyInt(),
- eq(R.string.accessibility_send_feedback_title));
- }
-
- @Test
- @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
- public void onOptionsItemSelected_enableLowVisionGenericFeedback_shouldStartSendFeedback() {
- mFragment.setFeedbackManager(
- new FeedbackManager(mActivity, PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CATEGORY));
- when(mMenuItem.getItemId()).thenReturn(
- ToggleFeaturePreferenceFragment.MENU_ID_SEND_FEEDBACK);
-
- mFragment.onOptionsItemSelected(mMenuItem);
-
- verify(mActivity).startActivityForResult(
- argThat(intent -> intent != null
- && Intent.ACTION_BUG_REPORT.equals(intent.getAction())), anyInt());
- }
-
- @Test
- @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
- public void onOptionsItemSelected_disableLowVisionGenericFeedback_shouldNotStartSendFeedback() {
- mFragment.setFeedbackManager(
- new FeedbackManager(mActivity, PLACEHOLDER_PACKAGE_NAME, PLACEHOLDER_CATEGORY));
- when(mMenuItem.getItemId()).thenReturn(
- ToggleFeaturePreferenceFragment.MENU_ID_SEND_FEEDBACK);
-
- mFragment.onOptionsItemSelected(mMenuItem);
-
- verify(mActivity, never()).startActivityForResult(
- argThat(intent -> intent != null
- && Intent.ACTION_BUG_REPORT.equals(intent.getAction())), anyInt());
- }
-
- @Test
public void updateShortcutPreferenceData_assignDefaultValueToVariable() {
mFragment.mComponentName = PLACEHOLDER_COMPONENT_NAME;
diff --git a/tests/robotests/src/com/android/settings/accessibility/actionbar/FeedbackMenuControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/actionbar/FeedbackMenuControllerTest.java
new file mode 100644
index 0000000..7208f49
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/actionbar/FeedbackMenuControllerTest.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2025 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.actionbar;
+
+import static com.android.settings.accessibility.actionbar.FeedbackMenuController.MENU_FEEDBACK;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.robolectric.Shadows.shadowOf;
+
+import android.app.settings.SettingsEnums;
+import android.content.Intent;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
+import android.platform.test.flag.junit.SetFlagsRule;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import androidx.fragment.app.FragmentActivity;
+import androidx.fragment.app.testing.EmptyFragmentActivity;
+import androidx.test.ext.junit.rules.ActivityScenarioRule;
+
+import com.android.settings.accessibility.FeedbackManager;
+import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+/** Tests for {@link FeedbackMenuController} */
+@Config(shadows = {
+ com.android.settings.testutils.shadow.ShadowFragment.class,
+})
+@RunWith(RobolectricTestRunner.class)
+public class FeedbackMenuControllerTest {
+ private static final String PACKAGE_NAME = "com.android.test";
+ private static final String DEFAULT_CATEGORY = "default category";
+
+ @Rule
+ public final MockitoRule mMocks = MockitoJUnit.rule();
+ @Rule
+ public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+ @Rule
+ public ActivityScenarioRule<EmptyFragmentActivity> mActivityScenario =
+ new ActivityScenarioRule<>(EmptyFragmentActivity.class);
+
+ private FragmentActivity mActivity;
+ private InstrumentedPreferenceFragment mHost;
+ private FeedbackManager mFeedbackManager;
+ @Mock
+ private Lifecycle mLifecycle;
+ @Mock
+ private Menu mMenu;
+ @Mock
+ private MenuItem mMenuItem;
+
+ @Before
+ public void setUp() {
+ mActivityScenario.getScenario().onActivity(activity -> mActivity = activity);
+ mHost = spy(new InstrumentedPreferenceFragment() {
+ @Override
+ public int getMetricsCategory() {
+ return 0;
+ }
+ });
+ when(mHost.getActivity()).thenReturn(mActivity);
+ when(mMenu.add(anyInt(), anyInt(), anyInt(), anyInt())).thenReturn(mMenuItem);
+ when(mMenuItem.getItemId()).thenReturn(MENU_FEEDBACK);
+ mFeedbackManager = new FeedbackManager(mActivity, PACKAGE_NAME, DEFAULT_CATEGORY);
+ }
+
+ @Test
+ public void init_withPageId_shouldAttachToLifecycle() {
+ when(mHost.getSettingsLifecycle()).thenReturn(mLifecycle);
+
+ FeedbackMenuController.init(mHost, SettingsEnums.ACCESSIBILITY);
+
+ verify(mLifecycle).addObserver(any(FeedbackMenuController.class));
+ }
+
+ @Test
+ public void init_withFeedbackManager_shouldAttachToLifecycle() {
+ when(mHost.getSettingsLifecycle()).thenReturn(mLifecycle);
+
+ FeedbackMenuController.init(mHost, mFeedbackManager);
+
+ verify(mLifecycle).addObserver(any(FeedbackMenuController.class));
+ }
+
+ @Test
+ @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
+ public void onCreateOptionsMenu_enableLowVisionGenericFeedback_shouldAddSendFeedbackMenu() {
+ FeedbackMenuController.init(mHost, mFeedbackManager);
+
+ mHost.getSettingsLifecycle().onCreateOptionsMenu(mMenu, /* inflater= */ null);
+
+ verify(mMenu).add(anyInt(), anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
+ public void onCreateOptionsMenu_disableLowVisionGenericFeedback_shouldNotAddSendFeedbackMenu() {
+ FeedbackMenuController.init(mHost, mFeedbackManager);
+
+ mHost.getSettingsLifecycle().onCreateOptionsMenu(mMenu, /* inflater= */ null);
+
+ verify(mMenu, never()).add(anyInt(), anyInt(), anyInt(), anyInt());
+ }
+
+ @Test
+ @EnableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
+ public void onOptionsItemSelected_enableLowVisionGenericFeedback_shouldStartSendFeedback() {
+ FeedbackMenuController.init(mHost, mFeedbackManager);
+
+ mHost.getSettingsLifecycle().onOptionsItemSelected(mMenuItem);
+
+ Intent intent = shadowOf(mActivity).getNextStartedActivity();
+ assertThat(intent.getAction()).isEqualTo(Intent.ACTION_BUG_REPORT);
+ }
+
+ @Test
+ @DisableFlags(com.android.server.accessibility.Flags.FLAG_ENABLE_LOW_VISION_GENERIC_FEEDBACK)
+ public void onOptionsItemSelected_disableLowVisionGenericFeedback_shouldNotStartSendFeedback() {
+ FeedbackMenuController.init(mHost, mFeedbackManager);
+
+ mHost.getSettingsLifecycle().onOptionsItemSelected(mMenuItem);
+
+ Intent intent = shadowOf(mActivity).getNextStartedActivity();
+ assertThat(intent).isNull();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt b/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt
index d0bd27d..1eb15e5 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt
+++ b/tests/robotests/src/com/android/settings/bluetooth/ui/view/DeviceDetailsFragmentFormatterTest.kt
@@ -16,7 +16,7 @@
package com.android.settings.bluetooth.ui.view
-import android.app.settings.SettingsEnums;
+import android.app.settings.SettingsEnums
import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.content.Intent
@@ -25,6 +25,7 @@
import androidx.preference.Preference
import androidx.preference.PreferenceManager
import androidx.preference.PreferenceScreen
+import androidx.preference.SwitchPreferenceCompat
import androidx.test.core.app.ApplicationProvider
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
@@ -33,6 +34,7 @@
import com.android.settingslib.bluetooth.CachedBluetoothDevice
import com.android.settingslib.bluetooth.devicesettings.DeviceSettingId
import com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingRepository
+import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingActionModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigItemModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingConfigModel
import com.android.settingslib.bluetooth.devicesettings.shared.model.DeviceSettingIcon
@@ -58,14 +60,15 @@
import org.mockito.Mockito.any
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
+import org.mockito.Spy
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.doNothing
import org.robolectric.Robolectric
import org.robolectric.RobolectricTestRunner
import org.robolectric.shadows.ShadowLooper
import org.robolectric.shadows.ShadowLooper.shadowMainLooper
-
@ExperimentalCoroutinesApi
@RunWith(RobolectricTestRunner::class)
class DeviceDetailsFragmentFormatterTest {
@@ -78,7 +81,7 @@
@Mock private lateinit var headerController: AbstractPreferenceController
@Mock private lateinit var buttonController: AbstractPreferenceController
- private lateinit var context: Context
+ @Spy private val context: Context = ApplicationProvider.getApplicationContext()
private lateinit var fragment: TestFragment
private lateinit var underTest: DeviceDetailsFragmentFormatter
private lateinit var featureFactory: FakeFeatureFactory
@@ -87,11 +90,15 @@
@Before
fun setUp() {
- context = ApplicationProvider.getApplicationContext()
featureFactory = FakeFeatureFactory.setupForTest()
+ doNothing().`when`(context).startActivity(any(Intent::class.java))
`when`(
featureFactory.bluetoothFeatureProvider.getDeviceSettingRepository(
- eq(context), eq(bluetoothAdapter), any()))
+ any(),
+ eq(bluetoothAdapter),
+ any(),
+ )
+ )
.thenReturn(repository)
fragmentActivity = Robolectric.setupActivity(FragmentActivity::class.java)
assertThat(fragmentActivity.applicationContext).isNotNull()
@@ -115,7 +122,8 @@
listOf(profileController, headerController, buttonController),
bluetoothAdapter,
cachedDevice,
- testScope.testScheduler)
+ testScope.testScheduler,
+ )
}
@Test
@@ -124,11 +132,16 @@
`when`(repository.getDeviceSettingsConfig(cachedDevice))
.thenReturn(
DeviceSettingConfigModel(
- listOf(), listOf(), DeviceSettingConfigItemModel.AppProvidedItem(12345, false)))
- val intent = Intent().apply {
- setAction(Intent.ACTION_VIEW)
- setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- }
+ listOf(),
+ listOf(),
+ DeviceSettingConfigItemModel.AppProvidedItem(12345, false),
+ )
+ )
+ val intent =
+ Intent().apply {
+ setAction(Intent.ACTION_VIEW)
+ setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
`when`(repository.getDeviceSetting(cachedDevice, 12345))
.thenReturn(
flowOf(
@@ -136,12 +149,15 @@
cachedDevice = cachedDevice,
id = 12345,
intent = intent,
- )))
+ )
+ )
+ )
var helpPreference: DeviceSettingPreferenceModel.HelpPreference? = null
- underTest.getMenuItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment).onEach {
- helpPreference = it
- }.launchIn(testScope.backgroundScope)
+ underTest
+ .getMenuItem(FragmentTypeModel.DeviceDetailsMoreSettingsFragment)
+ .onEach { helpPreference = it }
+ .launchIn(testScope.backgroundScope)
delay(100)
runCurrent()
ShadowLooper.idleMainLooper()
@@ -171,13 +187,19 @@
listOf(
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
DeviceSettingId.DEVICE_SETTING_ID_HEADER,
- highlighted = false, preferenceKey = "bluetooth_device_header"),
+ highlighted = false,
+ preferenceKey = "bluetooth_device_header",
+ ),
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES,
- highlighted = false, preferenceKey = "bluetooth_profiles"),
+ highlighted = false,
+ preferenceKey = "bluetooth_profiles",
+ ),
),
listOf(),
- null))
+ null,
+ )
+ )
underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
runCurrent()
@@ -189,13 +211,17 @@
SettingsEnums.PAGE_UNKNOWN,
SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_SHOWN,
0,
- "bluetooth_device_header", 1)
+ "bluetooth_device_header",
+ 1,
+ )
verify(featureFactory.metricsFeatureProvider)
.action(
SettingsEnums.PAGE_UNKNOWN,
SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_SHOWN,
0,
- "bluetooth_profiles", 1)
+ "bluetooth_profiles",
+ 1,
+ )
}
}
@@ -209,16 +235,22 @@
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
DeviceSettingId.DEVICE_SETTING_ID_HEADER,
highlighted = false,
- preferenceKey = "bluetooth_device_header"),
+ preferenceKey = "bluetooth_device_header",
+ ),
DeviceSettingConfigItemModel.AppProvidedItem(
- DeviceSettingId.DEVICE_SETTING_ID_ANC, highlighted = false),
+ DeviceSettingId.DEVICE_SETTING_ID_ANC,
+ highlighted = false,
+ ),
DeviceSettingConfigItemModel.BuiltinItem.CommonBuiltinItem(
DeviceSettingId.DEVICE_SETTING_ID_BLUETOOTH_PROFILES,
highlighted = false,
- preferenceKey = "bluetooth_profiles"),
+ preferenceKey = "bluetooth_profiles",
+ ),
),
listOf(),
- null))
+ null,
+ )
+ )
`when`(repository.getDeviceSetting(cachedDevice, DeviceSettingId.DEVICE_SETTING_ID_ANC))
.thenReturn(
flowOf(
@@ -231,11 +263,17 @@
ToggleModel(
"",
DeviceSettingIcon.BitmapIcon(
- Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)))),
+ Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
+ ),
+ )
+ ),
isActive = true,
state = DeviceSettingStateModel.MultiTogglePreferenceState(0),
isAllowedChangingState = true,
- updateState = {})))
+ updateState = {},
+ )
+ )
+ )
underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
runCurrent()
@@ -244,13 +282,119 @@
.containsExactly(
"bluetooth_device_header",
"DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}",
- "bluetooth_profiles")
+ "bluetooth_profiles",
+ )
verify(featureFactory.metricsFeatureProvider)
.action(
SettingsEnums.PAGE_UNKNOWN,
SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_SHOWN,
0,
- "DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}", 1
+ "DEVICE_SETTING_${DeviceSettingId.DEVICE_SETTING_ID_ANC}",
+ 1,
+ )
+ }
+ }
+
+ @Test
+ fun updateLayout_plainPreferenceClicked() {
+ testScope.runTest {
+ val settingId = 12345
+ val intent = Intent("test_intent")
+ `when`(repository.getDeviceSettingsConfig(cachedDevice))
+ .thenReturn(
+ DeviceSettingConfigModel(
+ listOf(
+ DeviceSettingConfigItemModel.AppProvidedItem(
+ settingId,
+ highlighted = false,
+ )
+ ),
+ listOf(),
+ null,
+ )
+ )
+
+ `when`(repository.getDeviceSetting(cachedDevice, settingId))
+ .thenReturn(
+ flowOf(
+ DeviceSettingModel.ActionSwitchPreference(
+ cachedDevice = cachedDevice,
+ id = settingId,
+ title = "title",
+ summary = "summary",
+ icon = null,
+ action = DeviceSettingActionModel.IntentAction(intent),
+ )
+ )
+ )
+
+ underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
+ runCurrent()
+ val displayedPrefs = getDisplayedPreferences()
+ displayedPrefs[0].performClick()
+
+ assertThat(displayedPrefs).hasSize(1)
+ verify(context).startActivity(intent)
+ verify(featureFactory.metricsFeatureProvider)
+ .action(
+ SettingsEnums.PAGE_UNKNOWN,
+ SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_CLICKED,
+ 0,
+ "DEVICE_SETTING_$settingId",
+ 2,
+ )
+ }
+ }
+
+ @Test
+ fun updateLayout_switchPreferenceClicked() {
+ val settingId = 12345
+ testScope.runTest {
+ `when`(repository.getDeviceSettingsConfig(cachedDevice))
+ .thenReturn(
+ DeviceSettingConfigModel(
+ listOf(
+ DeviceSettingConfigItemModel.AppProvidedItem(
+ settingId,
+ highlighted = false,
+ )
+ ),
+ listOf(),
+ null,
+ )
+ )
+
+ `when`(repository.getDeviceSetting(cachedDevice, settingId))
+ .thenReturn(
+ flowOf(
+ DeviceSettingModel.ActionSwitchPreference(
+ cachedDevice = cachedDevice,
+ id = settingId,
+ title = "title",
+ summary = "summary",
+ icon = null,
+ action = null,
+ switchState = DeviceSettingStateModel.ActionSwitchPreferenceState(true),
+ isAllowedChangingState = true,
+ updateState = {},
+ )
+ )
+ )
+
+ underTest.updateLayout(FragmentTypeModel.DeviceDetailsMainFragment)
+ runCurrent()
+ val displayedPrefs = getDisplayedPreferences()
+ displayedPrefs[0].performClick()
+
+ assertThat(displayedPrefs).hasSize(1)
+ assertThat(displayedPrefs[0]).isInstanceOf(SwitchPreferenceCompat::class.java)
+ verify(featureFactory.metricsFeatureProvider)
+ .action(
+ SettingsEnums.PAGE_UNKNOWN,
+ SettingsEnums.ACTION_BLUETOOTH_DEVICE_DETAILS_ITEM_CLICKED,
+ 0,
+ "DEVICE_SETTING_$settingId",
+ 0,
)
}
}
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModelTest.kt b/tests/robotests/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModelTest.kt
index caeea94..bf66a04 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModelTest.kt
+++ b/tests/robotests/src/com/android/settings/bluetooth/ui/viewmodel/BluetoothDeviceDetailsViewModelTest.kt
@@ -20,7 +20,6 @@
import android.bluetooth.BluetoothAdapter
import android.graphics.Bitmap
import androidx.test.core.app.ApplicationProvider
-import com.android.settings.bluetooth.ui.layout.DeviceSettingLayout
import com.android.settings.bluetooth.ui.model.DeviceSettingPreferenceModel
import com.android.settings.bluetooth.ui.model.FragmentTypeModel
import com.android.settings.testutils.FakeFeatureFactory
@@ -164,74 +163,6 @@
}
}
- @Test
- fun getLayout_builtinDeviceSettings() {
- testScope.runTest {
- `when`(repository.getDeviceSettingsConfig(cachedDevice))
- .thenReturn(
- DeviceSettingConfigModel(
- listOf(BUILTIN_SETTING_ITEM_1, BUILDIN_SETTING_ITEM_2), listOf(), null))
-
- val layout = underTest.getLayout(FragmentTypeModel.DeviceDetailsMainFragment)!!
-
- assertThat(getLatestLayout(layout))
- .isEqualTo(
- listOf(
- listOf(DeviceSettingId.DEVICE_SETTING_ID_HEADER),
- listOf(DeviceSettingId.DEVICE_SETTING_ID_ACTION_BUTTONS)))
- }
- }
-
- @Test
- fun getLayout_remoteDeviceSettings() {
- val remoteSettingId1 = 10001
- val remoteSettingId2 = 10002
- val remoteSettingId3 = 10003
- testScope.runTest {
- `when`(repository.getDeviceSettingsConfig(cachedDevice))
- .thenReturn(
- DeviceSettingConfigModel(
- listOf(
- BUILTIN_SETTING_ITEM_1,
- buildRemoteSettingItem(remoteSettingId1),
- buildRemoteSettingItem(remoteSettingId2),
- buildRemoteSettingItem(remoteSettingId3),
- ),
- listOf(),
- null))
- `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId1))
- .thenReturn(flowOf(buildMultiTogglePreference(remoteSettingId1)))
- `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId2))
- .thenReturn(flowOf(buildMultiTogglePreference(remoteSettingId2)))
- `when`(repository.getDeviceSetting(cachedDevice, remoteSettingId3))
- .thenReturn(flowOf(buildActionSwitchPreference(remoteSettingId3)))
-
- val layout = underTest.getLayout(FragmentTypeModel.DeviceDetailsMainFragment)!!
-
- assertThat(getLatestLayout(layout))
- .isEqualTo(
- listOf(
- listOf(DeviceSettingId.DEVICE_SETTING_ID_HEADER),
- listOf(remoteSettingId1),
- listOf(remoteSettingId2),
- listOf(remoteSettingId3),
- ))
- }
- }
-
- private fun getLatestLayout(layout: DeviceSettingLayout): List<List<Int>> {
- val latestLayout = MutableList(layout.rows.size) { emptyList<Int>() }
- for (i in layout.rows.indices) {
- layout.rows[i]
- .columns
- .onEach { latestLayout[i] = it.map { c -> c.settingId } }
- .launchIn(testScope.backgroundScope)
- }
-
- testScope.runCurrent()
- return latestLayout.filter { !it.isEmpty() }.toList()
- }
-
private fun buildMultiTogglePreference(settingId: Int) =
DeviceSettingModel.MultiTogglePreference(
cachedDevice,
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
index 15fe091..82642ee 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppPreferenceTest.kt
@@ -155,7 +155,7 @@
composeTestRule.onNode(
hasTextExactly(
- context.getString(R.string.aspect_ratio_experimental_title),
+ context.getString(R.string.aspect_ratio_title),
context.getString(R.string.user_aspect_ratio_app_default)
),
).assertIsDisplayed().assertIsEnabled()
diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
index b859df4..1549994 100644
--- a/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
+++ b/tests/spa_unit/src/com/android/settings/spa/app/appcompat/UserAspectRatioAppsPageProviderTest.kt
@@ -63,7 +63,7 @@
@Test
fun injectEntry_title() {
setInjectEntry()
- composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_experimental_title))
+ composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
.assertIsDisplayed()
}
@@ -78,7 +78,7 @@
@Test
fun injectEntry_onClick_navigate() {
setInjectEntry()
- composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_experimental_title))
+ composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
.performClick()
assertThat(fakeNavControllerWrapper.navigateCalledWith).isEqualTo("UserAspectRatioAppsPage")
}
@@ -97,7 +97,7 @@
UserAspectRatioAppList {}
}
- composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_experimental_title))
+ composeTestRule.onNodeWithText(context.getString(R.string.aspect_ratio_title))
.assertIsDisplayed()
}