Merge "Load icon from correct package for Accessibility slices" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 66c3beb..3f5cd84 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -783,9 +783,13 @@
<activity android:name="Settings$CombinedBiometricSettingsActivity"
android:label="@string/security_settings_biometric_preference_title"
- android:exported="false"
+ android:exported="true"
android:enableOnBackInvokedCallback="false"
android:taskAffinity="com.android.settings.root">
+ <intent-filter>
+ <action android:name="android.settings.COMBINED_BIOMETRICS_SETTINGS" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.biometrics.combination.CombinedBiometricSettings" />
<meta-data android:name="com.android.settings.HIGHLIGHT_MENU_KEY"
diff --git a/res/drawable/ic_pointer_and_touchpad.xml b/res/drawable/ic_pointer_and_touchpad.xml
new file mode 100644
index 0000000..c077900
--- /dev/null
+++ b/res/drawable/ic_pointer_and_touchpad.xml
@@ -0,0 +1,35 @@
+<!--
+ Copyright 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <com.android.settingslib.widget.AdaptiveIconShapeDrawable
+ android:width="@dimen/accessibility_icon_size"
+ android:height="@dimen/accessibility_icon_size"
+ android:color="@color/accessibility_feature_background"/>
+ </item>
+ <item android:gravity="center">
+ <vector
+ android:height="32dp"
+ android:width="32dp"
+ android:viewportHeight="32"
+ android:viewportWidth="32">
+ <path
+ android:fillColor="#fff"
+ android:pathData="M19.15,22.35a2.6,2.6 0,0 0,1.91 -0.79,2.6 2.6,0 0,0 0.79,-1.91v-0.9h-5.4v0.9c0,0.75 0.26,1.39 0.79,1.91a2.6,2.6 0,0 0,1.91 0.79ZM16.49,17.4h1.98v-2.17a2.6,2.6 0,0 0,-1.98 2.17ZM19.82,17.4h2a2.6,2.6 0,0 0,-0.68 -1.39,2.62 2.62,0 0,0 -1.32,-0.78v2.17ZM19.15,23.7a3.96,3.96 0,0 1,-4.05 -4.05v-1.8c0,-1.14 0.39,-2.1 1.16,-2.87a3.93,3.93 0,0 1,2.89 -1.18c1.14,0 2.1,0.4 2.87,1.18a3.87,3.87 0,0 1,1.18 2.87v1.8c0,1.14 -0.4,2.1 -1.18,2.89a3.9,3.9 0,0 1,-2.87 1.16ZM10.15,20.55v-8.1,8.1ZM10.15,21.9c-0.38,0 -0.7,-0.13 -0.96,-0.4s-0.39,-0.59 -0.39,-0.95v-8.1c0,-0.36 0.13,-0.67 0.4,-0.94 0.26,-0.27 0.57,-0.41 0.95,-0.41h11.7c0.37,0 0.7,0.14 0.96,0.41 0.26,0.27 0.39,0.58 0.39,0.94L10.15,12.45v8.1h3.6v1.35h-3.6Z"/>
+ </vector>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/layout/main_clear_confirm.xml b/res/layout/main_clear_confirm.xml
index 6027d18..d482132 100644
--- a/res/layout/main_clear_confirm.xml
+++ b/res/layout/main_clear_confirm.xml
@@ -19,21 +19,5 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
- android:id="@+id/setup_wizard_layout"
android:icon="@drawable/ic_delete_accent"
- app:sucHeaderText="@string/main_clear_confirm_title">
-
- <LinearLayout
- style="@style/SudContentFrame"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <TextView
- android:id="@+id/sud_layout_subtitle"
- style="@style/TextAppearance.PreferenceTitle.SettingsLib"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/main_clear_final_desc"/>
- </LinearLayout>
-</com.google.android.setupdesign.GlifLayout>
+ app:sucHeaderText="@string/main_clear_confirm_title" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 3494afd..0999f0a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -4532,8 +4532,8 @@
<string name="trackpad_bottom_right_tap_summary">Click in the bottom right corner of the touchpad for more options</string>
<!-- Title text for 'Pointer speed'. [CHAR LIMIT=35] -->
<string name="trackpad_pointer_speed">Pointer speed</string>
- <!-- Title text for mouse pointer fill style. [CHAR LIMIT=35] -->
- <string name="pointer_fill_style">Pointer fill style</string>
+ <!-- Title text for mouse pointer color. [CHAR LIMIT=35] -->
+ <string name="pointer_fill_style">Pointer color</string>
<!-- Content description for black pointer fill style. [CHAR LIMIT=60] -->
<string name="pointer_fill_style_black_button">Change pointer fill style to black</string>
<!-- Content description for green pointer fill style. [CHAR LIMIT=60] -->
@@ -4810,6 +4810,12 @@
<string name="display_category_title">Display</string>
<!-- Title for the accessibility color and motion page. [CHAR LIMIT=50] -->
<string name="accessibility_color_and_motion_title">Color and motion</string>
+ <!-- Title for the accessibility pointer and touchpad page. [CHAR LIMIT=50] -->
+ <string name="accessibility_pointer_and_touchpad_title">Pointer & touchpad accessibility</string>
+ <!-- Summary for the accessibility pointer and touchpad page. [CHAR LIMIT=50] -->
+ <string name="accessibility_pointer_and_touchpad_summary">Pointer color, pointer size & more</string>
+ <!-- Title for the accessibility pointer color customization page. [CHAR LIMIT=50] -->
+ <string name="accessibility_pointer_color_customization_title">Pointer color customization</string>
<!-- Title for the accessibility color contrast page. [CHAR LIMIT=50] -->
<string name="accessibility_color_contrast_title">Color contrast</string>
<!-- Intro for the accessibility color contrast page. [CHAR LIMIT=NONE] -->
@@ -13360,9 +13366,9 @@
<!-- Summary of the Live Caption enabled state. -->
<string name="live_caption_enabled">On</string>
<!-- State description for the Audio Balance seek bar, with left reported before right. -->
- <string name="audio_seek_bar_state_left_first">Audio %1$d%% left, %2$d%% right</string>
+ <string name="audio_seek_bar_state_left_first">Audio <xliff:g id="percent_left">%1$s</xliff:g> left, <xliff:g id="percent_right">%2$s</xliff:g> right</string>
<!-- State description for the Audio Balance seek bar, with right reported before left. -->
- <string name="audio_seek_bar_state_right_first">Audio %1$d%% right, %2$d%% left</string>
+ <string name="audio_seek_bar_state_right_first">Audio <xliff:g id="percent_right">%1$s</xliff:g> right, <xliff:g id="percent_left">%2$s</xliff:g> left</string>
<!-- Warning text about the visibility of device name. [CHAR LIMIT=NONE] -->
<string name="about_phone_device_name_warning">Your device name is visible to apps you installed. It may also be seen by other people when you connect to Bluetooth devices, connect to a Wi-Fi network or set up a Wi-Fi hotspot.</string>
diff --git a/res/xml/accessibility_color_and_motion.xml b/res/xml/accessibility_color_and_motion.xml
index 4c4490c..a500b72 100644
--- a/res/xml/accessibility_color_and_motion.xml
+++ b/res/xml/accessibility_color_and_motion.xml
@@ -72,17 +72,6 @@
android:title="@string/accessibility_toggle_large_pointer_icon_title"
settings:controller="com.android.settings.accessibility.LargePointerIconPreferenceController"/>
- <com.android.settings.widget.LabeledSeekBarPreference
- android:key="large_pointer_scale"
- android:title="@string/accessibility_toggle_large_pointer_icon_title"
- android:summary="@string/accessibility_toggle_large_pointer_icon_summary"
- android:max="@integer/pointer_scale_seek_bar_end"
- settings:iconStart="@drawable/ic_remove_24dp"
- settings:iconStartContentDescription="@string/pointer_scale_decrease_content_description"
- settings:iconEnd="@drawable/ic_add_24dp"
- settings:iconEndContentDescription="@string/pointer_scale_increase_content_description"
- settings:controller="com.android.settings.inputmethod.PointerScaleSeekBarController" />
-
<PreferenceCategory
android:key="experimental_category"
android:persistent="false"
diff --git a/res/xml/accessibility_pointer_and_touchpad.xml b/res/xml/accessibility_pointer_and_touchpad.xml
new file mode 100644
index 0000000..1d3b0f2
--- /dev/null
+++ b/res/xml/accessibility_pointer_and_touchpad.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="accessibility_pointer_and_touchpad"
+ android:persistent="false"
+ android:title="@string/accessibility_pointer_and_touchpad_title">
+
+ <com.android.settings.widget.LabeledSeekBarPreference
+ android:key="pointer_scale_preference"
+ android:title="@string/pointer_scale"
+ android:max="@integer/pointer_scale_seek_bar_end"
+ settings:iconStart="@drawable/ic_remove_24dp"
+ settings:iconStartContentDescription="@string/pointer_scale_decrease_content_description"
+ settings:iconEnd="@drawable/ic_add_24dp"
+ settings:iconEndContentDescription="@string/pointer_scale_increase_content_description"
+ settings:controller="com.android.settings.inputmethod.PointerScaleSeekBarController" />
+
+ <Preference
+ android:fragment="com.android.settings.inputmethod.PointerColorCustomizationFragment"
+ android:key="pointer_color_customization_preference"
+ android:persistent="false"
+ android:title="@string/accessibility_pointer_color_customization_title"/>
+
+ <Preference
+ android:fragment="com.android.settings.accessibility.ToggleAutoclickPreferenceFragment"
+ android:key="autoclick_preference"
+ android:persistent="false"
+ android:title="@string/accessibility_autoclick_preference_title"
+ settings:keywords="@string/keywords_auto_click"
+ settings:controller="com.android.settings.accessibility.AutoclickPreferenceController"/>
+
+</PreferenceScreen>
diff --git a/res/xml/accessibility_pointer_color_customization.xml b/res/xml/accessibility_pointer_color_customization.xml
new file mode 100644
index 0000000..6d767b4
--- /dev/null
+++ b/res/xml/accessibility_pointer_color_customization.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 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.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="accessibility_pointer_color_customization"
+ android:persistent="false"
+ android:title="@string/accessibility_pointer_color_customization_title">
+
+ <com.android.settings.inputmethod.PointerFillStylePreference
+ android:key="pointer_fill_style"
+ android:title="@string/pointer_fill_style"
+ settings:controller="com.android.settings.inputmethod.PointerFillStylePreferenceController"/>
+
+ <com.android.settings.inputmethod.PointerStrokeStylePreference
+ android:key="pointer_stroke_style"
+ android:title="@string/pointer_stroke_style"
+ settings:controller="com.android.settings.inputmethod.PointerStrokeStylePreferenceController"/>
+
+</PreferenceScreen>
diff --git a/res/xml/accessibility_settings.xml b/res/xml/accessibility_settings.xml
index 6561775..18e6455 100644
--- a/res/xml/accessibility_settings.xml
+++ b/res/xml/accessibility_settings.xml
@@ -110,6 +110,16 @@
settings:keywords="@string/keywords_vibration"
android:summary="@string/accessibility_vibration_settings_summary"/>
+ <Preference
+ android:fragment="com.android.settings.inputmethod.PointerTouchpadFragment"
+ android:key="pointer_and_touchpad"
+ android:icon="@drawable/ic_pointer_and_touchpad"
+ android:persistent="false"
+ android:title="@string/accessibility_pointer_and_touchpad_title"
+ android:summary="@string/accessibility_pointer_and_touchpad_summary"
+ settings:controller="com.android.settings.inputmethod.PointerTouchpadPreferenceController"
+ settings:searchable="true"/>
+
</PreferenceCategory>
<PreferenceCategory
diff --git a/res/xml/accessibility_tap_assistance.xml b/res/xml/accessibility_tap_assistance.xml
index d2ec653..6a53d83 100644
--- a/res/xml/accessibility_tap_assistance.xml
+++ b/res/xml/accessibility_tap_assistance.xml
@@ -37,12 +37,4 @@
android:title="@string/accessibility_setting_item_control_timeout_title"
settings:controller="com.android.settings.accessibility.AccessibilityTimeoutPreferenceController"
settings:keywords="@string/keywords_accessibility_timeout"/>
-
- <Preference
- android:fragment="com.android.settings.accessibility.ToggleAutoclickPreferenceFragment"
- android:key="autoclick_preference"
- android:persistent="false"
- android:title="@string/accessibility_autoclick_preference_title"
- settings:keywords="@string/keywords_auto_click"
- settings:controller="com.android.settings.accessibility.AutoclickPreferenceController"/>
</PreferenceScreen>
\ No newline at end of file
diff --git a/res/xml/trackpad_settings.xml b/res/xml/trackpad_settings.xml
index 935de82..7e94944 100644
--- a/res/xml/trackpad_settings.xml
+++ b/res/xml/trackpad_settings.xml
@@ -62,29 +62,14 @@
android:selectable="false"
settings:controller="com.android.settings.inputmethod.TrackpadPointerSpeedPreferenceController"/>
- <com.android.settings.inputmethod.PointerFillStylePreference
- android:key="pointer_fill_style"
- android:title="@string/pointer_fill_style"
+ <Preference
+ android:fragment="com.android.settings.inputmethod.PointerTouchpadFragment"
+ android:key="pointer_and_touchpad"
android:order="50"
- settings:controller="com.android.settings.inputmethod.PointerFillStylePreferenceController"/>
-
- <com.android.settings.inputmethod.PointerStrokeStylePreference
- android:key="pointer_stroke_style"
- android:title="@string/pointer_stroke_style"
- android:order="60"
- settings:controller="com.android.settings.inputmethod.PointerStrokeStylePreferenceController"/>
-
- <com.android.settings.widget.LabeledSeekBarPreference
- android:key="pointer_scale"
- android:title="@string/pointer_scale"
- android:order="70"
- android:max="@integer/pointer_scale_seek_bar_end"
- settings:iconStart="@drawable/ic_remove_24dp"
- settings:searchable="false"
- settings:iconStartContentDescription="@string/pointer_scale_decrease_content_description"
- settings:iconEnd="@drawable/ic_add_24dp"
- settings:iconEndContentDescription="@string/pointer_scale_increase_content_description"
- settings:controller="com.android.settings.inputmethod.PointerScaleSeekBarController" />
+ android:persistent="false"
+ android:title="@string/accessibility_pointer_and_touchpad_title"
+ android:summary="@string/accessibility_pointer_and_touchpad_summary"
+ settings:searchable="true"/>
<com.android.settingslib.widget.ButtonPreference
android:key="trackpad_touch_gesture"
diff --git a/src/com/android/settings/FallbackHome.java b/src/com/android/settings/FallbackHome.java
index b70470b..d62b6c2 100644
--- a/src/com/android/settings/FallbackHome.java
+++ b/src/com/android/settings/FallbackHome.java
@@ -179,6 +179,8 @@
SystemClock.uptimeMillis(), false);
finish();
}
+ } else {
+ Log.d(TAG, "User not yet unlocked");
}
}
diff --git a/src/com/android/settings/MainClearConfirm.java b/src/com/android/settings/MainClearConfirm.java
index a5fbebf..c9887e8 100644
--- a/src/com/android/settings/MainClearConfirm.java
+++ b/src/com/android/settings/MainClearConfirm.java
@@ -19,8 +19,6 @@
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
-import android.app.ActionBar;
-import android.app.Activity;
import android.app.ProgressDialog;
import android.app.admin.DevicePolicyManager;
import android.app.admin.FactoryResetProtectionPolicy;
@@ -28,7 +26,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemProperties;
@@ -36,12 +33,10 @@
import android.os.UserManager;
import android.service.oemlock.OemLockManager;
import android.service.persistentdata.PersistentDataBlockManager;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
-import android.widget.TextView;
import androidx.annotation.VisibleForTesting;
@@ -62,7 +57,7 @@
* has defined one, followed by a final strongly-worded "THIS WILL ERASE EVERYTHING
* ON THE PHONE" prompt. If at any time the phone is allowed to go to sleep, is
* locked, et cetera, then the confirmation sequence is abandoned.
- *
+ * <p>
* This is the confirmation screen.
*/
public class MainClearConfirm extends InstrumentedFragment {
@@ -70,9 +65,11 @@
private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
- @VisibleForTesting View mContentView;
+ @VisibleForTesting
+ GlifLayout mContentView;
private boolean mEraseSdCard;
- @VisibleForTesting boolean mEraseEsims;
+ @VisibleForTesting
+ boolean mEraseEsims;
/**
* The user has gone through the multiple confirmation, so now we go ahead
@@ -215,9 +212,7 @@
* Configure the UI for the final confirmation interaction
*/
private void establishFinalConfirmationState() {
- final GlifLayout layout = mContentView.findViewById(R.id.setup_wizard_layout);
-
- final FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class);
+ final FooterBarMixin mixin = mContentView.getMixin(FooterBarMixin.class);
mixin.setPrimaryButton(
new FooterButton.Builder(getActivity())
.setText(R.string.main_clear_button_text)
@@ -228,21 +223,6 @@
);
}
- private void setUpActionBarAndTitle() {
- final Activity activity = getActivity();
- if (activity == null) {
- Log.e(TAG, "No activity attached, skipping setUpActionBarAndTitle");
- return;
- }
- final ActionBar actionBar = activity.getActionBar();
- if (actionBar == null) {
- Log.e(TAG, "No actionbar, skipping setUpActionBarAndTitle");
- return;
- }
- actionBar.hide();
- activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
- }
-
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
@@ -258,32 +238,26 @@
.show();
return new View(getActivity());
}
- mContentView = inflater.inflate(R.layout.main_clear_confirm, null);
- setUpActionBarAndTitle();
+ mContentView = (GlifLayout) inflater.inflate(R.layout.main_clear_confirm, null);
establishFinalConfirmationState();
- setAccessibilityTitle();
setSubtitle();
+ setAccessibilityTitle();
return mContentView;
}
private void setAccessibilityTitle() {
CharSequence currentTitle = getActivity().getTitle();
- TextView confirmationMessage = mContentView.findViewById(R.id.sud_layout_description);
+ CharSequence confirmationMessage = mContentView.getDescriptionText();
if (confirmationMessage != null) {
- String accessibleText = new StringBuilder(currentTitle).append(",").append(
- confirmationMessage.getText()).toString();
+ String accessibleText = currentTitle + "," + confirmationMessage;
getActivity().setTitle(Utils.createAccessibleSequence(currentTitle, accessibleText));
}
}
@VisibleForTesting
void setSubtitle() {
- if (mEraseEsims) {
- TextView confirmationMessage = mContentView.findViewById(R.id.sud_layout_description);
- if (confirmationMessage != null) {
- confirmationMessage.setText(R.string.main_clear_final_desc_esim);
- }
- }
+ mContentView.setDescriptionText(
+ mEraseEsims ? R.string.main_clear_final_desc_esim : R.string.main_clear_final_desc);
}
@Override
diff --git a/src/com/android/settings/accessibility/BalanceSeekBar.java b/src/com/android/settings/accessibility/BalanceSeekBar.java
index 7441d6f..8f8f767 100644
--- a/src/com/android/settings/accessibility/BalanceSeekBar.java
+++ b/src/com/android/settings/accessibility/BalanceSeekBar.java
@@ -36,6 +36,7 @@
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
+import com.android.settings.Utils;
/**
* A custom seekbar for the balance setting.
@@ -178,10 +179,12 @@
== LAYOUT_DIRECTION_RTL;
final int rightPercent = (int) (100 * (progress / max));
final int leftPercent = 100 - rightPercent;
+ final String rightPercentString = Utils.formatPercentage(rightPercent);
+ final String leftPercentString = Utils.formatPercentage(leftPercent);
if (rightPercent > leftPercent || (rightPercent == leftPercent && isLayoutRtl)) {
- return context.getString(resIdRightFirst, rightPercent, leftPercent);
+ return context.getString(resIdRightFirst, rightPercentString, leftPercentString);
} else {
- return context.getString(resIdLeftFirst, leftPercent, rightPercent);
+ return context.getString(resIdLeftFirst, leftPercentString, rightPercentString);
}
}
}
diff --git a/src/com/android/settings/accessibility/FloatingMenuFadePreferenceController.java b/src/com/android/settings/accessibility/FloatingMenuFadePreferenceController.java
index 70882a4..2ef0858 100644
--- a/src/com/android/settings/accessibility/FloatingMenuFadePreferenceController.java
+++ b/src/com/android/settings/accessibility/FloatingMenuFadePreferenceController.java
@@ -67,14 +67,11 @@
@Override
public CharSequence getSummary() {
- if (mPreference != null) {
- return mPreference.isEnabled()
- ? "%s"
- : mContext.getString(
- R.string.accessibility_button_disabled_button_mode_summary);
- } else {
- return "%s";
+ int rId = R.string.accessibility_button_fade_summary;
+ if (mPreference != null && !mPreference.isEnabled()) {
+ rId = R.string.accessibility_button_disabled_button_mode_summary;
}
+ return mContext.getString(rId);
}
@Override
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragment.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragment.java
index b00f407..79cc56e 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragment.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragment.java
@@ -44,7 +44,7 @@
private static final String TAG = "AudioSharingLoadingDlg";
private static final String BUNDLE_KEY_MESSAGE = "bundle_key_message";
- private static final long AUTO_DISMISS_TIME_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(10);
+ private static final long AUTO_DISMISS_TIME_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(15);
private static final int AUTO_DISMISS_MESSAGE_ID = R.id.message;
private static String sMessage = "";
@@ -74,13 +74,15 @@
}
AlertDialog dialog = AudioSharingDialogHelper.getDialogIfShowing(manager, TAG);
if (dialog != null) {
- if (sMessage.equals(message)) {
- Log.d(TAG, "Dialog is showing with same message, return.");
- return;
- } else {
- Log.d(TAG, "Dialog is showing with different message, dismiss and reshow.");
- dialog.dismiss();
+ if (!sMessage.equals(message)) {
+ Log.d(TAG, "Update dialog message.");
+ TextView messageView = dialog.findViewById(R.id.message);
+ if (messageView != null) {
+ messageView.setText(message);
+ }
}
+ Log.d(TAG, "Dialog is showing, return.");
+ return;
}
sMessage = message;
Log.d(TAG, "Show up the loading dialog.");
@@ -113,8 +115,10 @@
@NonNull
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
mHandler = new Handler(Looper.getMainLooper());
- mHandler.postDelayed(() -> dismiss(), AUTO_DISMISS_MESSAGE_ID,
- AUTO_DISMISS_TIME_THRESHOLD_MS);
+ mHandler.postDelayed(() -> {
+ Log.d(TAG, "Auto dismiss dialog after timeout");
+ dismiss();
+ }, AUTO_DISMISS_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS);
Bundle args = requireArguments();
String message = args.getString(BUNDLE_KEY_MESSAGE, "");
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
@@ -132,6 +136,7 @@
public void onDismiss(@NonNull DialogInterface dialog) {
super.onDismiss(dialog);
if (mHandler != null) {
+ Log.d(TAG, "Dialog dismissed, remove auto dismiss task");
mHandler.removeMessages(AUTO_DISMISS_MESSAGE_ID);
}
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
index 2040694..c0f463d 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarController.java
@@ -70,6 +70,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -112,12 +113,13 @@
private final MetricsFeatureProvider mMetricsFeatureProvider;
private final OnAudioSharingStateChangedListener mListener;
private Map<Integer, List<BluetoothDevice>> mGroupedConnectedDevices = new HashMap<>();
- private List<BluetoothDevice> mTargetActiveSinks = new ArrayList<>();
+ @Nullable private AudioSharingDeviceItem mTargetActiveItem;
private List<AudioSharingDeviceItem> mDeviceItemsForSharing = new ArrayList<>();
@VisibleForTesting IntentFilter mIntentFilter;
private final AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false);
private AtomicInteger mIntentHandleStage =
new AtomicInteger(StartIntentHandleStage.TO_HANDLE.ordinal());
+ private CopyOnWriteArrayList<BluetoothDevice> mSinksInAdding = new CopyOnWriteArrayList<>();
@VisibleForTesting
BroadcastReceiver mReceiver =
@@ -294,7 +296,16 @@
public void onReceiveStateChanged(
@NonNull BluetoothDevice sink,
int sourceId,
- @NonNull BluetoothLeBroadcastReceiveState state) {}
+ @NonNull BluetoothLeBroadcastReceiveState state) {
+ if (BluetoothUtils.isConnected(state)) {
+ if (mSinksInAdding.contains(sink)) {
+ mSinksInAdding.remove(sink);
+ }
+ dismissLoadingStateDialogIfNeeded();
+ Log.d(TAG, "onReceiveStateChanged() connected, sink = " + sink
+ + ", remaining sinks = " + mSinksInAdding);
+ }
+ }
};
AudioSharingSwitchBarController(
@@ -506,17 +517,20 @@
mBtManager, mGroupedConnectedDevices, /* filterByInSharing= */ false);
// deviceItems is ordered. The active device is the first place if exits.
mDeviceItemsForSharing = new ArrayList<>(deviceItems);
- mTargetActiveSinks = new ArrayList<>();
+ mTargetActiveItem = null;
if (!deviceItems.isEmpty() && deviceItems.get(0).isActive()) {
// If active device exists for audio sharing, share to it
// automatically once the broadcast is started.
- mTargetActiveSinks =
- mGroupedConnectedDevices.getOrDefault(
- deviceItems.get(0).getGroupId(), ImmutableList.of());
+ mTargetActiveItem = deviceItems.get(0);
mDeviceItemsForSharing.remove(0);
}
if (mBroadcast != null) {
mBroadcast.startPrivateBroadcast();
+ mSinksInAdding.clear();
+ // TODO: use string res once finalized.
+ AudioSharingUtils.postOnMainThread(mContext,
+ () -> AudioSharingLoadingStateDialogFragment.show(mFragment,
+ "Starting audio stream..."));
mMetricsFeatureProvider.action(
mContext,
SettingsEnums.ACTION_AUDIO_SHARING_MAIN_SWITCH_ON,
@@ -580,27 +594,30 @@
}
private void handleOnBroadcastReady() {
+ List<BluetoothDevice> targetActiveSinks = mTargetActiveItem == null ? ImmutableList.of()
+ : mGroupedConnectedDevices.getOrDefault(
+ mTargetActiveItem.getGroupId(), ImmutableList.of());
Pair<Integer, Object>[] eventData =
AudioSharingUtils.buildAudioSharingDialogEventData(
SettingsEnums.AUDIO_SHARING_SETTINGS,
SettingsEnums.DIALOG_AUDIO_SHARING_ADD_DEVICE,
/* userTriggered= */ false,
- /* deviceCountInSharing= */ mTargetActiveSinks.isEmpty() ? 0 : 1,
+ /* deviceCountInSharing= */ targetActiveSinks.isEmpty() ? 0 : 1,
/* candidateDeviceCount= */ mDeviceItemsForSharing.size());
- if (!mTargetActiveSinks.isEmpty()) {
+ if (!targetActiveSinks.isEmpty() && mTargetActiveItem != null) {
Log.d(TAG, "handleOnBroadcastReady: automatically add source to active sinks.");
- AudioSharingUtils.addSourceToTargetSinks(mTargetActiveSinks, mBtManager);
+ addSourceToTargetSinks(targetActiveSinks, mTargetActiveItem.getName());
mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING);
- mTargetActiveSinks.clear();
+ mTargetActiveItem = null;
if (mIntentHandleStage.compareAndSet(
StartIntentHandleStage.HANDLE_AUTO_ADD.ordinal(),
StartIntentHandleStage.HANDLED.ordinal())
&& mDeviceItemsForSharing.size() == 1) {
Log.d(TAG, "handleOnBroadcastReady: auto add source to the second device");
- AudioSharingUtils.addSourceToTargetSinks(
- mGroupedConnectedDevices.getOrDefault(
- mDeviceItemsForSharing.get(0).getGroupId(), ImmutableList.of()),
- mBtManager);
+ AudioSharingDeviceItem target = mDeviceItemsForSharing.get(0);
+ List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault(
+ target.getGroupId(), ImmutableList.of());
+ addSourceToTargetSinks(targetSinks, target.getName());
cleanUp();
// TODO: Add metric for auto add by intent
return;
@@ -611,6 +628,7 @@
StartIntentHandleStage.HANDLED.ordinal());
if (mFragment == null) {
Log.d(TAG, "handleOnBroadcastReady: dialog fail to show due to null fragment.");
+ dismissLoadingStateDialogIfNeeded();
cleanUp();
return;
}
@@ -622,15 +640,15 @@
new AudioSharingDialogFragment.DialogEventListener() {
@Override
public void onItemClick(@NonNull AudioSharingDeviceItem item) {
- AudioSharingUtils.addSourceToTargetSinks(
- mGroupedConnectedDevices.getOrDefault(
- item.getGroupId(), ImmutableList.of()),
- mBtManager);
+ List<BluetoothDevice> targetSinks = mGroupedConnectedDevices.getOrDefault(
+ item.getGroupId(), ImmutableList.of());
+ addSourceToTargetSinks(targetSinks, item.getName());
cleanUp();
}
@Override
public void onCancelClick() {
+ dismissLoadingStateDialogIfNeeded();
cleanUp();
}
};
@@ -700,6 +718,27 @@
});
}
+ private void addSourceToTargetSinks(List<BluetoothDevice> targetActiveSinks,
+ @NonNull String sinkName) {
+ mSinksInAdding.addAll(targetActiveSinks);
+ AudioSharingUtils.addSourceToTargetSinks(targetActiveSinks, mBtManager);
+ // TODO: move to res once finalized
+ String loadingMessage = "Sharing with " + sinkName + "...";
+ showLoadingStateDialog(loadingMessage);
+ }
+
+ private void showLoadingStateDialog(@NonNull String loadingMessage) {
+ AudioSharingUtils.postOnMainThread(mContext,
+ () -> AudioSharingLoadingStateDialogFragment.show(mFragment, loadingMessage));
+ }
+
+ private void dismissLoadingStateDialogIfNeeded() {
+ if (mSinksInAdding.isEmpty()) {
+ AudioSharingUtils.postOnMainThread(mContext,
+ () -> AudioSharingLoadingStateDialogFragment.dismiss(mFragment));
+ }
+ }
+
private void cleanUp() {
mGroupedConnectedDevices.clear();
mDeviceItemsForSharing.clear();
diff --git a/src/com/android/settings/inputmethod/PointerColorCustomizationFragment.java b/src/com/android/settings/inputmethod/PointerColorCustomizationFragment.java
new file mode 100644
index 0000000..2324c5e
--- /dev/null
+++ b/src/com/android/settings/inputmethod/PointerColorCustomizationFragment.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 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.inputmethod;
+
+import static com.android.settings.inputmethod.NewKeyboardSettingsUtils.isMouse;
+import static com.android.settings.inputmethod.NewKeyboardSettingsUtils.isTouchpad;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.search.SearchIndexable;
+
+/** Settings for pointer and touchpad. */
+@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
+public class PointerColorCustomizationFragment extends DashboardFragment {
+
+ private static final String TAG = "PointerColorCustomizationFragment";
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.ACCESSIBILITY_POINTER_COLOR_CUSTOMIZATION;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.accessibility_pointer_color_customization;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+
+ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider(R.xml.accessibility_pointer_color_customization) {
+ @Override
+ protected boolean isPageSearchEnabled(Context context) {
+ return isTouchpad() || isMouse();
+ }
+ };
+}
diff --git a/src/com/android/settings/inputmethod/PointerTouchpadFragment.java b/src/com/android/settings/inputmethod/PointerTouchpadFragment.java
new file mode 100644
index 0000000..fc069ca
--- /dev/null
+++ b/src/com/android/settings/inputmethod/PointerTouchpadFragment.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 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.inputmethod;
+
+import static com.android.settings.inputmethod.NewKeyboardSettingsUtils.isMouse;
+import static com.android.settings.inputmethod.NewKeyboardSettingsUtils.isTouchpad;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.search.SearchIndexable;
+
+/** Accessibility settings for pointer and touchpad. */
+@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
+public class PointerTouchpadFragment extends DashboardFragment {
+
+ private static final String TAG = "PointerTouchpadFragment";
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.ACCESSIBILITY_POINTER_TOUCHPAD;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.accessibility_pointer_and_touchpad;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider(R.xml.accessibility_pointer_and_touchpad) {
+ @Override
+ protected boolean isPageSearchEnabled(Context context) {
+ return isTouchpad() || isMouse();
+ }
+ };
+}
diff --git a/src/com/android/settings/inputmethod/PointerTouchpadPreferenceController.java b/src/com/android/settings/inputmethod/PointerTouchpadPreferenceController.java
new file mode 100644
index 0000000..b6ea063
--- /dev/null
+++ b/src/com/android/settings/inputmethod/PointerTouchpadPreferenceController.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 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.inputmethod;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.android.settings.core.BasePreferenceController;
+
+/** Controller that shows and updates the pointer touchpad preference. */
+public class PointerTouchpadPreferenceController extends BasePreferenceController {
+
+ public PointerTouchpadPreferenceController(@NonNull Context context,
+ @NonNull String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ boolean isTouchpad = NewKeyboardSettingsUtils.isTouchpad();
+ boolean isMouse = NewKeyboardSettingsUtils.isMouse();
+ return (isTouchpad || isMouse) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+}
diff --git a/src/com/android/settings/network/SubscriptionInfoListViewModel.kt b/src/com/android/settings/network/SubscriptionInfoListViewModel.kt
index df3b8ba..fe50522 100644
--- a/src/com/android/settings/network/SubscriptionInfoListViewModel.kt
+++ b/src/com/android/settings/network/SubscriptionInfoListViewModel.kt
@@ -20,7 +20,7 @@
import android.telephony.SubscriptionManager
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.viewModelScope
-import com.android.settings.network.telephony.getSelectableSubscriptionInfoList
+import com.android.settings.network.telephony.SubscriptionRepository
import com.android.settings.network.telephony.subscriptionsChangedFlow
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
@@ -45,7 +45,8 @@
* Getting the Selectable SubscriptionInfo List from the SubscriptionRepository's
* getAvailableSubscriptionInfoList
*/
- val selectableSubscriptionInfoListFlow = application.subscriptionsChangedFlow().map {
- application.getSelectableSubscriptionInfoList()
- }.stateIn(scope, SharingStarted.Eagerly, initialValue = emptyList())
+ val selectableSubscriptionInfoListFlow =
+ SubscriptionRepository(application)
+ .selectableSubscriptionInfoListFlow()
+ .stateIn(scope, SharingStarted.Eagerly, initialValue = emptyList())
}
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index fcf1599..aca2fc3 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -52,7 +52,7 @@
import com.android.settings.network.helper.SubscriptionAnnotation;
import com.android.settings.network.telephony.DeleteEuiccSubscriptionDialogActivity;
import com.android.settings.network.telephony.EuiccRacConnectivityDialogActivity;
-import com.android.settings.network.telephony.SubscriptionRepositoryKt;
+import com.android.settings.network.telephony.SubscriptionRepository;
import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity;
import java.util.ArrayList;
@@ -508,7 +508,7 @@
* @return list of user selectable subscriptions.
*/
public static List<SubscriptionInfo> getSelectableSubscriptionInfoList(Context context) {
- return SubscriptionRepositoryKt.getSelectableSubscriptionInfoList(context);
+ return new SubscriptionRepository(context).getSelectableSubscriptionInfoList();
}
/**
diff --git a/src/com/android/settings/network/telephony/SubscriptionRepository.kt b/src/com/android/settings/network/telephony/SubscriptionRepository.kt
index 26ea9b3..6b5b4cb 100644
--- a/src/com/android/settings/network/telephony/SubscriptionRepository.kt
+++ b/src/com/android/settings/network/telephony/SubscriptionRepository.kt
@@ -42,13 +42,48 @@
class SubscriptionRepository(private val context: Context) {
private val subscriptionManager = context.requireSubscriptionManager()
+ /** A cold flow of a list of subscriptions that are available and visible to the user. */
+ fun selectableSubscriptionInfoListFlow(): Flow<List<SubscriptionInfo>> =
+ context
+ .subscriptionsChangedFlow()
+ .map { getSelectableSubscriptionInfoList() }
+ .conflate()
+ .flowOn(Dispatchers.Default)
+
/**
* Return a list of subscriptions that are available and visible to the user.
*
* @return list of user selectable subscriptions.
*/
- fun getSelectableSubscriptionInfoList(): List<SubscriptionInfo> =
- context.getSelectableSubscriptionInfoList()
+ fun getSelectableSubscriptionInfoList(): List<SubscriptionInfo> {
+ val availableList =
+ subscriptionManager.getAvailableSubscriptionInfoList() ?: return emptyList()
+ val visibleList =
+ availableList.filter { subInfo ->
+ // Opportunistic subscriptions are considered invisible to users so they should
+ // never be returned.
+ SubscriptionUtil.isSubscriptionVisible(subscriptionManager, context, subInfo)
+ }
+ return visibleList
+ .groupBy { it.groupUuid }
+ .flatMap { (groupUuid, subInfos) ->
+ if (groupUuid == null) {
+ subInfos
+ } else {
+ // Multiple subscriptions in a group should only have one representative.
+ // It should be the current active primary subscription if any, or the primary
+ // subscription with minimum subscription id.
+ subInfos
+ .filter { it.simSlotIndex != SubscriptionManager.INVALID_SIM_SLOT_INDEX }
+ .ifEmpty { subInfos.sortedBy { it.subscriptionId } }
+ .take(1)
+ }
+ }
+ // Matching the sorting order in
+ // SubscriptionManagerService.getAvailableSubscriptionInfoList
+ .sortedWith(compareBy({ it.sortableSimSlotIndex }, { it.subscriptionId }))
+ .also { Log.d(TAG, "getSelectableSubscriptionInfoList: $it") }
+ }
/** Flow of whether the subscription visible for the given [subId]. */
fun isSubscriptionVisibleFlow(subId: Int): Flow<Boolean> {
@@ -154,38 +189,6 @@
fun Context.subscriptionsChangedFlow(): Flow<Unit> =
SubscriptionRepository(this).subscriptionsChangedFlow()
-/**
- * Return a list of subscriptions that are available and visible to the user.
- *
- * @return list of user selectable subscriptions.
- */
-fun Context.getSelectableSubscriptionInfoList(): List<SubscriptionInfo> {
- val subscriptionManager = requireSubscriptionManager()
- val availableList = subscriptionManager.getAvailableSubscriptionInfoList() ?: return emptyList()
- val visibleList = availableList.filter { subInfo ->
- // Opportunistic subscriptions are considered invisible
- // to users so they should never be returned.
- SubscriptionUtil.isSubscriptionVisible(subscriptionManager, this, subInfo)
- }
- return visibleList
- .groupBy { it.groupUuid }
- .flatMap { (groupUuid, subInfos) ->
- if (groupUuid == null) {
- subInfos
- } else {
- // Multiple subscriptions in a group should only have one representative.
- // It should be the current active primary subscription if any, or the primary
- // subscription with minimum subscription id.
- subInfos.filter { it.simSlotIndex != SubscriptionManager.INVALID_SIM_SLOT_INDEX }
- .ifEmpty { subInfos.sortedBy { it.subscriptionId } }
- .take(1)
- }
- }
- // Matching the sorting order in SubscriptionManagerService.getAvailableSubscriptionInfoList
- .sortedWith(compareBy({ it.sortableSimSlotIndex }, { it.subscriptionId }))
- .also { Log.d(TAG, "getSelectableSubscriptionInfoList: $it") }
-}
-
/** Subscription with invalid sim slot index has lowest sort order. */
private val SubscriptionInfo.sortableSimSlotIndex: Int
get() = if (simSlotIndex != SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
diff --git a/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceController.java
index 68cc167..9355b1b 100644
--- a/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceController.java
@@ -58,6 +58,5 @@
conditionId -> saveMode(mode -> {
mode.setCustomModeConditionId(mContext, conditionId);
return mode;
- // TODO: b/342156843 - Maybe jump to the corresponding schedule editing screen?
});
}
diff --git a/src/com/android/settings/notification/modes/ZenModesListFragment.java b/src/com/android/settings/notification/modes/ZenModesListFragment.java
index 37772b3..89cb662 100644
--- a/src/com/android/settings/notification/modes/ZenModesListFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModesListFragment.java
@@ -142,9 +142,6 @@
@Override
public List<String> getNonIndexableKeys(Context context) {
final List<String> keys = super.getNonIndexableKeys(context);
- // TODO: b/332937523 - determine if this should be removed once the preference
- // controller adds dynamic data to index
- keys.add(ZenModesListPreferenceController.KEY);
return keys;
}
diff --git a/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceController.java b/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceController.java
index a41a0b2..560f313 100644
--- a/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceController.java
+++ b/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceController.java
@@ -20,6 +20,7 @@
import android.content.Context;
+import androidx.fragment.app.Fragment;
import androidx.preference.Preference;
import androidx.preference.TwoStatePreference;
@@ -28,7 +29,6 @@
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settingslib.core.AbstractPreferenceController;
-import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
/**
* Preference controller for the pin_auto_confirm setting.
@@ -40,11 +40,10 @@
private final int mUserId;
private final LockPatternUtils mLockPatternUtils;
- private final ObservablePreferenceFragment mParentFragment;
+ private final Fragment mParentFragment;
public AutoPinConfirmPreferenceController(Context context, int userId,
- LockPatternUtils lockPatternUtils,
- ObservablePreferenceFragment parentFragment) {
+ LockPatternUtils lockPatternUtils, Fragment parentFragment) {
super(context);
mUserId = userId;
mLockPatternUtils = lockPatternUtils;
diff --git a/src/com/android/settings/support/actionbar/HelpMenuController.java b/src/com/android/settings/support/actionbar/HelpMenuController.java
deleted file mode 100644
index 7e1f460..0000000
--- a/src/com/android/settings/support/actionbar/HelpMenuController.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2017 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.support.actionbar;
-
-import static com.android.settings.support.actionbar.HelpResourceProvider.HELP_URI_RESOURCE_KEY;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.Menu;
-import android.view.MenuInflater;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-
-import com.android.settingslib.HelpUtils;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.ObservableFragment;
-import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
-import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu;
-
-/**
- * A controller that adds help menu to any Settings page.
- */
-public class HelpMenuController implements LifecycleObserver, OnCreateOptionsMenu {
-
- private final Fragment mHost;
-
- public static void init(@NonNull ObservablePreferenceFragment host) {
- host.getSettingsLifecycle().addObserver(new HelpMenuController(host));
- }
-
- public static void init(@NonNull ObservableFragment host) {
- host.getSettingsLifecycle().addObserver(new HelpMenuController(host));
- }
-
- private HelpMenuController(@NonNull Fragment host) {
- mHost = host;
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- final Bundle arguments = mHost.getArguments();
- int helpResourceId = 0;
- if (arguments != null && arguments.containsKey(HELP_URI_RESOURCE_KEY)) {
- helpResourceId = arguments.getInt(HELP_URI_RESOURCE_KEY);
- } else if (mHost instanceof HelpResourceProvider) {
- helpResourceId = ((HelpResourceProvider) mHost).getHelpResource();
- }
-
- String helpUri = null;
- if (helpResourceId != 0) {
- helpUri = mHost.getContext().getString(helpResourceId);
- }
- final Activity activity = mHost.getActivity();
- if (helpUri != null && activity != null) {
- HelpUtils.prepareHelpMenuItem(activity, menu, helpUri, mHost.getClass().getName());
- }
- }
-}
diff --git a/tests/robotests/src/com/android/settings/MainClearConfirmTest.java b/tests/robotests/src/com/android/settings/MainClearConfirmTest.java
index f7711c8..a102fda 100644
--- a/tests/robotests/src/com/android/settings/MainClearConfirmTest.java
+++ b/tests/robotests/src/com/android/settings/MainClearConfirmTest.java
@@ -31,10 +31,11 @@
import android.security.Flags;
import android.service.persistentdata.PersistentDataBlockManager;
import android.view.LayoutInflater;
-import android.widget.TextView;
import androidx.fragment.app.FragmentActivity;
+import com.google.android.setupdesign.GlifLayout;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -85,12 +86,12 @@
MainClearConfirm mainClearConfirm = new MainClearConfirm();
mainClearConfirm.mEraseEsims = true;
mainClearConfirm.mContentView =
- LayoutInflater.from(mActivity).inflate(R.layout.main_clear_confirm, null);
+ (GlifLayout) LayoutInflater.from(mActivity)
+ .inflate(R.layout.main_clear_confirm, null);
mainClearConfirm.setSubtitle();
- assertThat(((TextView) mainClearConfirm.mContentView
- .findViewById(R.id.sud_layout_description)).getText())
+ assertThat(mainClearConfirm.mContentView.getDescriptionText())
.isEqualTo(mActivity.getString(R.string.main_clear_final_desc_esim));
}
@@ -99,12 +100,12 @@
MainClearConfirm mainClearConfirm = new MainClearConfirm();
mainClearConfirm.mEraseEsims = false;
mainClearConfirm.mContentView =
- LayoutInflater.from(mActivity).inflate(R.layout.main_clear_confirm, null);
+ (GlifLayout) LayoutInflater.from(mActivity)
+ .inflate(R.layout.main_clear_confirm, null);
mainClearConfirm.setSubtitle();
- assertThat(((TextView) mainClearConfirm.mContentView
- .findViewById(R.id.sud_layout_description)).getText())
+ assertThat(mainClearConfirm.mContentView.getDescriptionText())
.isEqualTo(mActivity.getString(R.string.main_clear_final_desc));
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarTest.java b/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarTest.java
index d74794f..bbe511d 100644
--- a/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/BalanceSeekBarTest.java
@@ -34,6 +34,7 @@
import android.widget.SeekBar;
import com.android.settings.R;
+import com.android.settings.Utils;
import com.android.settings.testutils.shadow.ShadowSystemSettings;
import org.junit.Before;
@@ -162,7 +163,8 @@
mProxySeekBarListener.onProgressChanged(mSeekBar, progress, true);
assertThat(mSeekBar.getStateDescription()).isEqualTo(
- mContext.getString(R.string.audio_seek_bar_state_left_first, 50, 50));
+ mContext.getString(R.string.audio_seek_bar_state_left_first,
+ Utils.formatPercentage(50), Utils.formatPercentage(50)));
}
@Test
@@ -177,7 +179,8 @@
mProxySeekBarListener.onProgressChanged(mSeekBar, progress, true);
assertThat(mSeekBar.getStateDescription()).isEqualTo(
- mContext.getString(R.string.audio_seek_bar_state_right_first, 50, 50));
+ mContext.getString(R.string.audio_seek_bar_state_right_first,
+ Utils.formatPercentage(50), Utils.formatPercentage(50)));
}
@Test
@@ -189,7 +192,8 @@
mProxySeekBarListener.onProgressChanged(mSeekBar, progress, true);
assertThat(mSeekBar.getStateDescription()).isEqualTo(
- mContext.getString(R.string.audio_seek_bar_state_left_first, 75, 25));
+ mContext.getString(R.string.audio_seek_bar_state_left_first,
+ Utils.formatPercentage(75), Utils.formatPercentage(25)));
}
@Test
@@ -201,7 +205,8 @@
mProxySeekBarListener.onProgressChanged(mSeekBar, progress, true);
assertThat(mSeekBar.getStateDescription()).isEqualTo(
- mContext.getString(R.string.audio_seek_bar_state_right_first, 75, 25));
+ mContext.getString(R.string.audio_seek_bar_state_right_first,
+ Utils.formatPercentage(75), Utils.formatPercentage(25)));
}
// method to get the center from BalanceSeekBar for testing setMax().
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragmentTest.java
index b5da88c..ff15f52 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingLoadingStateDialogFragmentTest.java
@@ -150,7 +150,7 @@
}
@Test
- public void showDialog_newMessage_dismissAndShowNewDialog() {
+ public void showDialog_newMessage_keepAndUpdateDialog() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE1);
shadowMainLooper().idle();
@@ -163,12 +163,7 @@
AudioSharingLoadingStateDialogFragment.show(mParent, TEST_MESSAGE2);
shadowMainLooper().idle();
- assertThat(dialog.isShowing()).isFalse();
- AlertDialog newDialog = ShadowAlertDialogCompat.getLatestAlertDialog();
- assertThat(newDialog).isNotNull();
- assertThat(newDialog.isShowing()).isTrue();
- view = newDialog.findViewById(R.id.message);
- assertThat(view).isNotNull();
+ assertThat(dialog.isShowing()).isTrue();
assertThat(view.getText().toString()).isEqualTo(TEST_MESSAGE2);
}
}
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java
index 354c5c7..0d21f18 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingSwitchBarControllerTest.java
@@ -57,7 +57,9 @@
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.widget.CompoundButton;
+import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
@@ -235,6 +237,7 @@
@After
public void tearDown() {
+ ShadowAlertDialogCompat.reset();
ShadowBluetoothUtils.reset();
ShadowThreadUtils.reset();
}
@@ -426,6 +429,8 @@
assertThat(childFragments)
.comparingElementsUsing(CLAZZNAME_EQUALS)
.containsExactly(AudioSharingConfirmDialogFragment.class.getName());
+
+ childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss());
}
@Test
@@ -490,14 +495,21 @@
public void onAudioSharingProfilesConnected() {}
});
mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
+ shadowOf(Looper.getMainLooper()).idle();
+
verify(mBroadcast).startPrivateBroadcast();
+ List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
+ // No loading state dialog.
+ assertThat(childFragments).isEmpty();
+
mController.mBroadcastCallback.onPlaybackStarted(0, 0);
shadowOf(Looper.getMainLooper()).idle();
verify(mFeatureFactory.metricsFeatureProvider)
.action(any(Context.class), eq(SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING));
- List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
+ childFragments = mParentFragment.getChildFragmentManager().getFragments();
+ // No audio sharing dialog.
assertThat(childFragments).isEmpty();
}
@@ -514,7 +526,13 @@
when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
doNothing().when(mBroadcast).startPrivateBroadcast();
mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
+ shadowOf(Looper.getMainLooper()).idle();
+
verify(mBroadcast).startPrivateBroadcast();
+ List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
+ assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
+ AudioSharingLoadingStateDialogFragment.class.getName());
+
mController.mBroadcastCallback.onPlaybackStarted(0, 0);
shadowOf(Looper.getMainLooper()).idle();
@@ -522,8 +540,12 @@
verify(mFeatureFactory.metricsFeatureProvider, never())
.action(any(Context.class), eq(SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING));
- List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
- assertThat(childFragments).isEmpty();
+ childFragments = mParentFragment.getChildFragmentManager().getFragments();
+ // No audio sharing dialog.
+ assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).doesNotContain(
+ AudioSharingDialogFragment.class.getName());
+
+ childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss());
}
@Test
@@ -534,23 +556,42 @@
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1));
when(mAssistant.getAllSources(any(BluetoothDevice.class))).thenReturn(ImmutableList.of());
doNothing().when(mBroadcast).startPrivateBroadcast();
- mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
+ mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
+ shadowOf(Looper.getMainLooper()).idle();
+
verify(mBroadcast).startPrivateBroadcast();
+ List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
+ assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
+ AudioSharingLoadingStateDialogFragment.class.getName());
+ AudioSharingLoadingStateDialogFragment loadingFragment =
+ (AudioSharingLoadingStateDialogFragment) Iterables.getOnlyElement(childFragments);
+ // TODO: use string res once finalized
+ String expectedMessage = "Starting audio stream...";
+ checkLoadingStateDialogMessage(loadingFragment, expectedMessage);
+
mController.mBroadcastCallback.onPlaybackStarted(0, 0);
shadowOf(Looper.getMainLooper()).idle();
verify(mFeatureFactory.metricsFeatureProvider)
.action(any(Context.class), eq(SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING));
+ // TODO: use string res once finalized
+ expectedMessage = "Sharing with " + TEST_DEVICE_NAME2 + "...";
+ checkLoadingStateDialogMessage(loadingFragment, expectedMessage);
- List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
+ childFragments = mParentFragment.getChildFragmentManager().getFragments();
assertThat(childFragments)
.comparingElementsUsing(CLAZZNAME_EQUALS)
- .containsExactly(AudioSharingDialogFragment.class.getName());
+ .containsExactly(AudioSharingDialogFragment.class.getName(),
+ AudioSharingLoadingStateDialogFragment.class.getName());
- AudioSharingDialogFragment fragment =
- (AudioSharingDialogFragment) Iterables.getOnlyElement(childFragments);
- Pair<Integer, Object>[] eventData = fragment.getEventData();
+ Pair<Integer, Object>[] eventData = new Pair[0];
+ for (Fragment fragment : childFragments) {
+ if (fragment instanceof AudioSharingDialogFragment) {
+ eventData = ((AudioSharingDialogFragment) fragment).getEventData();
+ break;
+ }
+ }
assertThat(eventData)
.asList()
.containsExactly(
@@ -570,6 +611,8 @@
AudioSharingUtils.MetricKey.METRIC_KEY_CANDIDATE_DEVICE_COUNT
.ordinal(),
1));
+
+ childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss());
}
@Test
@@ -582,6 +625,8 @@
when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
doNothing().when(mBroadcast).startPrivateBroadcast();
mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
+ shadowOf(Looper.getMainLooper()).idle();
+
verify(mBroadcast).startPrivateBroadcast();
mController.mBroadcastCallback.onPlaybackStarted(0, 0);
shadowOf(Looper.getMainLooper()).idle();
@@ -597,6 +642,17 @@
verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false);
assertThat(dialog.isShowing()).isFalse();
+ // Loading state dialog shows sharing state for the user chosen sink.
+ List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
+ assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
+ AudioSharingLoadingStateDialogFragment.class.getName());
+ AudioSharingLoadingStateDialogFragment loadingFragment =
+ (AudioSharingLoadingStateDialogFragment) Iterables.getOnlyElement(childFragments);
+ // TODO: use string res once finalized
+ String expectedMessage = "Sharing with " + TEST_DEVICE_NAME1 + "...";
+ checkLoadingStateDialogMessage(loadingFragment, expectedMessage);
+
+ childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss());
}
@Test
@@ -609,6 +665,8 @@
when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
doNothing().when(mBroadcast).startPrivateBroadcast();
mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
+ shadowOf(Looper.getMainLooper()).idle();
+
verify(mBroadcast).startPrivateBroadcast();
mController.mBroadcastCallback.onPlaybackStarted(0, 0);
shadowOf(Looper.getMainLooper()).idle();
@@ -624,10 +682,21 @@
verify(mAssistant, never()).addSource(mDevice1, mMetadata, /* isGroupOp= */ false);
assertThat(dialog.isShowing()).isFalse();
+ // Loading state dialog shows sharing state for the auto add active sink.
+ List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
+ assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
+ AudioSharingLoadingStateDialogFragment.class.getName());
+ AudioSharingLoadingStateDialogFragment loadingFragment =
+ (AudioSharingLoadingStateDialogFragment) Iterables.getOnlyElement(childFragments);
+ // TODO: use string res once finalized
+ String expectedMessage = "Sharing with " + TEST_DEVICE_NAME2 + "...";
+ checkLoadingStateDialogMessage(loadingFragment, expectedMessage);
+
+ childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss());
}
@Test
- public void testBluetoothLeBroadcastCallbacks_updateSwitch() {
+ public void testBroadcastCallbacks_updateSwitch() {
mOnAudioSharingStateChanged = false;
mSwitchBar.setChecked(false);
when(mBroadcast.isEnabled(any())).thenReturn(false);
@@ -673,7 +742,7 @@
}
@Test
- public void testBluetoothLeBroadcastCallbacks_doNothing() {
+ public void testBroadcastCallbacks_doNothing() {
mController.mBroadcastCallback.onBroadcastMetadataChanged(/* reason= */ 1, mMetadata);
mController.mBroadcastCallback.onBroadcastUpdated(/* reason= */ 1, /* broadcastId= */ 1);
mController.mBroadcastCallback.onPlaybackStarted(/* reason= */ 1, /* broadcastId= */ 1);
@@ -685,7 +754,7 @@
}
@Test
- public void testBluetoothLeBroadcastAssistantCallbacks_logAction() {
+ public void testAssistantCallbacks_onSourceAddFailed_logAction() {
mController.mBroadcastAssistantCallback.onSourceAddFailed(
mDevice1, mMetadata, /* reason= */ 1);
verify(mFeatureFactory.metricsFeatureProvider)
@@ -696,7 +765,24 @@
}
@Test
- public void testBluetoothLeBroadcastAssistantCallbacks_doNothing() {
+ public void testAssistantCallbacks_onReceiveStateChanged_dismissLoadingDialog() {
+ AudioSharingLoadingStateDialogFragment.show(mParentFragment, TEST_DEVICE_NAME1);
+ shadowOf(Looper.getMainLooper()).idle();
+ List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
+ assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
+ AudioSharingLoadingStateDialogFragment.class.getName());
+
+ BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+ when(state.getBisSyncState()).thenReturn(ImmutableList.of(1L));
+ mController.mBroadcastAssistantCallback.onReceiveStateChanged(mDevice1, /* sourceId= */ 1,
+ state);
+ shadowOf(Looper.getMainLooper()).idle();
+ childFragments = mParentFragment.getChildFragmentManager().getFragments();
+ assertThat(childFragments).isEmpty();
+ }
+
+ @Test
+ public void testAssistantCallbacks_doNothing() {
BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
// Do nothing
@@ -784,7 +870,7 @@
@Test
public void handleStartAudioSharingFromIntent_flagOff_doNothing() {
mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
- setUpStartSharingIntent();
+ var unused = setUpFragmentWithStartSharingIntent();
mController.onStart(mLifecycleOwner);
shadowOf(Looper.getMainLooper()).idle();
@@ -795,7 +881,7 @@
public void handleStartAudioSharingFromIntent_profileNotReady_doNothing() {
mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mAssistant.isProfileReady()).thenReturn(false);
- setUpStartSharingIntent();
+ var unused = setUpFragmentWithStartSharingIntent();
mController.onServiceConnected();
shadowOf(Looper.getMainLooper()).idle();
@@ -817,13 +903,16 @@
when(mBtnView.isEnabled()).thenReturn(true);
when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice2, mDevice1));
when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(mMetadata);
- setUpStartSharingIntent();
+ Fragment parentFragment = setUpFragmentWithStartSharingIntent();
mController.onServiceConnected();
shadowOf(Looper.getMainLooper()).idle();
verify(mSwitchBar).setChecked(true);
doNothing().when(mBroadcast).startPrivateBroadcast();
mController.onCheckedChanged(mBtnView, /* isChecked= */ true);
+ shadowOf(Looper.getMainLooper()).idle();
+
+ verify(mBroadcast).startPrivateBroadcast();
mController.mBroadcastCallback.onPlaybackStarted(0, 0);
shadowOf(Looper.getMainLooper()).idle();
@@ -831,11 +920,21 @@
.action(any(Context.class), eq(SettingsEnums.ACTION_AUTO_JOIN_AUDIO_SHARING));
verify(mAssistant).addSource(mDevice1, mMetadata, /* isGroupOp= */ false);
verify(mAssistant).addSource(mDevice2, mMetadata, /* isGroupOp= */ false);
- List<Fragment> childFragments = mParentFragment.getChildFragmentManager().getFragments();
- assertThat(childFragments).isEmpty();
+ List<Fragment> childFragments = parentFragment.getChildFragmentManager().getFragments();
+ // Skip audio sharing dialog.
+ assertThat(childFragments).comparingElementsUsing(CLAZZNAME_EQUALS).containsExactly(
+ AudioSharingLoadingStateDialogFragment.class.getName());
+ // The loading state dialog shows sharing state for the auto add second sink.
+ AudioSharingLoadingStateDialogFragment loadingFragment =
+ (AudioSharingLoadingStateDialogFragment) Iterables.getOnlyElement(childFragments);
+ // TODO: use string res once finalized
+ String expectedMessage = "Sharing with " + TEST_DEVICE_NAME1 + "...";
+ checkLoadingStateDialogMessage(loadingFragment, expectedMessage);
+
+ childFragments.forEach(fragment -> ((DialogFragment) fragment).dismiss());
}
- private void setUpStartSharingIntent() {
+ private Fragment setUpFragmentWithStartSharingIntent() {
Bundle args = new Bundle();
args.putBoolean(EXTRA_START_LE_AUDIO_SHARING, true);
Intent intent = new Intent();
@@ -849,5 +948,15 @@
.get();
shadowOf(Looper.getMainLooper()).idle();
mController.init(fragment);
+ return fragment;
+ }
+
+ private void checkLoadingStateDialogMessage(
+ @NonNull AudioSharingLoadingStateDialogFragment fragment,
+ @NonNull String expectedMessage) {
+ TextView loadingMessage = fragment.getDialog() == null ? null
+ : fragment.getDialog().findViewById(R.id.message);
+ assertThat(loadingMessage).isNotNull();
+ assertThat(loadingMessage.getText().toString()).isEqualTo(expectedMessage);
}
}
diff --git a/tests/robotests/src/com/android/settings/inputmethod/PointerTouchpadFragmentTest.java b/tests/robotests/src/com/android/settings/inputmethod/PointerTouchpadFragmentTest.java
new file mode 100644
index 0000000..68cd768
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/inputmethod/PointerTouchpadFragmentTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright 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.inputmethod;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.settings.SettingsEnums;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class PointerTouchpadFragmentTest {
+
+ private PointerTouchpadFragment mFragment;
+
+ @Before
+ public void setUp() {
+ mFragment = new PointerTouchpadFragment();
+ }
+
+ @Test
+ public void getPreferenceScreenResId_isPointerTouchpad() {
+ assertThat(mFragment.getPreferenceScreenResId())
+ .isEqualTo(R.xml.accessibility_pointer_and_touchpad);
+ }
+
+ @Test
+ public void getMetricsCategory_returnsCorrectCategory() {
+ assertThat(mFragment.getMetricsCategory()).isEqualTo(
+ SettingsEnums.ACCESSIBILITY_POINTER_TOUCHPAD);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/inputmethod/PointerTouchpadPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/inputmethod/PointerTouchpadPreferenceControllerTest.java
new file mode 100644
index 0000000..6fceeba
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/inputmethod/PointerTouchpadPreferenceControllerTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 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.inputmethod;
+
+import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.view.InputDevice;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.testutils.shadow.ShadowInputDevice;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+/** Tests for {@link PointerTouchpadPreferenceController}. */
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {
+ ShadowInputDevice.class,
+})
+public final class PointerTouchpadPreferenceControllerTest {
+ @Rule public MockitoRule rule = MockitoJUnit.rule();
+
+ private PointerTouchpadPreferenceController mController;
+
+ @Before
+ public void initObjects() {
+ Context context = ApplicationProvider.getApplicationContext();
+ mController = new PointerTouchpadPreferenceController(context, "pointer_touchpad");
+ ShadowInputDevice.reset();
+ }
+
+ @Test
+ public void getAvailableStatus_noTouchpadOrMouseConditionallyUnavailable() {
+ int deviceId = 1;
+ ShadowInputDevice.sDeviceIds = new int[]{deviceId};
+ InputDevice device = ShadowInputDevice.makeInputDevicebyIdWithSources(deviceId,
+ InputDevice.SOURCE_BLUETOOTH_STYLUS);
+ ShadowInputDevice.addDevice(deviceId, device);
+
+ assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_isTouchpadAvailable() {
+ int deviceId = 1;
+ ShadowInputDevice.sDeviceIds = new int[]{deviceId};
+ InputDevice device = ShadowInputDevice.makeInputDevicebyIdWithSources(deviceId,
+ InputDevice.SOURCE_TOUCHPAD);
+ ShadowInputDevice.addDevice(deviceId, device);
+
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.AVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_isMouseAvailable() {
+ int deviceId = 1;
+ ShadowInputDevice.sDeviceIds = new int[]{deviceId};
+ InputDevice device = ShadowInputDevice.makeInputDevicebyIdWithSources(deviceId,
+ InputDevice.SOURCE_MOUSE);
+ ShadowInputDevice.addDevice(deviceId, device);
+
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.AVAILABLE);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceControllerTest.java
index 86c1244..0e0ed69 100644
--- a/tests/robotests/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceControllerTest.java
@@ -22,11 +22,11 @@
import android.content.Context;
+import androidx.fragment.app.Fragment;
import androidx.preference.SwitchPreference;
import androidx.test.core.app.ApplicationProvider;
import com.android.internal.widget.LockPatternUtils;
-import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
import org.junit.Before;
import org.junit.Test;
@@ -41,7 +41,7 @@
@Mock
private LockPatternUtils mLockPatternUtils;
@Mock
- private ObservablePreferenceFragment mParentFragment;
+ private Fragment mParentFragment;
private AutoPinConfirmPreferenceController mController;
private SwitchPreference mPreference;
diff --git a/tests/robotests/src/com/android/settings/support/actionbar/HelpMenuControllerTest.java b/tests/robotests/src/com/android/settings/support/actionbar/HelpMenuControllerTest.java
deleted file mode 100644
index 8cd26da..0000000
--- a/tests/robotests/src/com/android/settings/support/actionbar/HelpMenuControllerTest.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2017 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.support.actionbar;
-
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.os.Bundle;
-
-import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-
-@RunWith(RobolectricTestRunner.class)
-public class HelpMenuControllerTest {
-
- @Mock
- private Context mContext;
- private TestFragment mHost;
-
- @Before
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mHost = spy(new TestFragment());
- doReturn(mContext).when(mHost).getContext();
- }
-
- @Test
- public void onCreateOptionsMenu_withArgumentOverride_shouldPrepareHelpUsingOverride() {
- final Bundle bundle = new Bundle();
- bundle.putInt(HelpResourceProvider.HELP_URI_RESOURCE_KEY, 123);
- mHost.setArguments(bundle);
-
- HelpMenuController.init(mHost);
-
- mHost.getSettingsLifecycle().onCreateOptionsMenu(null /* menu */, null /* inflater */);
-
- verify(mContext).getString(123);
- }
-
- @Test
- public void onCreateOptionsMenu_noArgumentOverride_shouldPrepareHelpUsingProvider() {
- HelpMenuController.init(mHost);
-
- mHost.getSettingsLifecycle().onCreateOptionsMenu(null /* menu */, null /* inflater */);
-
- verify(mContext).getString(mHost.getHelpResource());
- }
-
- private static class TestFragment extends ObservablePreferenceFragment
- implements HelpResourceProvider {
-
- @Override
- public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
- }
- }
-}
diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt
index 5dbc534..5052f57 100644
--- a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt
+++ b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionRepositoryTest.kt
@@ -120,7 +120,7 @@
)
}
- val subInfos = context.getSelectableSubscriptionInfoList()
+ val subInfos = repository.getSelectableSubscriptionInfoList()
assertThat(subInfos.map { it.simSlotIndex })
.containsExactly(SIM_SLOT_INDEX_0, SIM_SLOT_INDEX_1).inOrder()
@@ -141,7 +141,7 @@
)
}
- val subInfos = context.getSelectableSubscriptionInfoList()
+ val subInfos = repository.getSelectableSubscriptionInfoList()
assertThat(subInfos.map { it.simSlotIndex })
.containsExactly(SIM_SLOT_INDEX_1, SubscriptionManager.INVALID_SIM_SLOT_INDEX).inOrder()
@@ -164,7 +164,7 @@
)
}
- val subInfos = context.getSelectableSubscriptionInfoList()
+ val subInfos = repository.getSelectableSubscriptionInfoList()
assertThat(subInfos.map { it.subscriptionId }).containsExactly(SUB_ID_IN_SLOT_0)
}
@@ -184,7 +184,7 @@
)
}
- val subInfos = context.getSelectableSubscriptionInfoList()
+ val subInfos = repository.getSelectableSubscriptionInfoList()
assertThat(subInfos.map { it.subscriptionId }).containsExactly(SUB_ID_3_NOT_IN_SLOT)
}