Merge "Add ethernet interface details settings subpage" into main
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index de54b83..47d3360 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -5538,10 +5538,14 @@
</service>
<receiver android:name="com.android.settings.connecteddevice.audiosharing.AudioSharingReceiver"
- android:exported="true">
+ android:permission="android.permission.BLUETOOTH_PRIVILEGED"
+ android:exported="true"> <!-- Exported for SystemUI. -->
<intent-filter>
<action android:name="com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STATE_CHANGE" />
<action android:name="com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STOP" />
+ <action android:name="com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_DEVICE_CONNECTED" />
+ <action android:name="com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_ADD_SOURCE" />
+ <action android:name="com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_CANCEL_NOTIF" />
</intent-filter>
</receiver>
diff --git a/aconfig/settings_communal_flag_declarations.aconfig b/aconfig/settings_communal_flag_declarations.aconfig
index 3d3a805..fff8f49 100644
--- a/aconfig/settings_communal_flag_declarations.aconfig
+++ b/aconfig/settings_communal_flag_declarations.aconfig
@@ -1,5 +1,5 @@
package: "com.android.settings.flags"
-container: "system"
+container: "system_ext"
flag {
name: "enable_hub_mode_settings_on_mobile"
diff --git a/res/color/color_battery_anomaly_app_warning_selector.xml b/res/color/color_battery_anomaly_app_warning_selector.xml
deleted file mode 100644
index 4ad78e6..0000000
--- a/res/color/color_battery_anomaly_app_warning_selector.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="@color/power_anomaly_app_warning_hint_color"/>
-</selector>
diff --git a/res/drawable/ic_battery_tips_warning_icon.xml b/res/drawable/ic_battery_tips_warning_icon.xml
index 0dcfa6d..1555930 100644
--- a/res/drawable/ic_battery_tips_warning_icon.xml
+++ b/res/drawable/ic_battery_tips_warning_icon.xml
@@ -20,6 +20,6 @@
android:viewportWidth="960"
android:viewportHeight="960">
<path
- android:fillColor="@color/color_battery_anomaly_app_warning_selector"
+ android:fillColor="@color/settingslib_colorBackgroundLevel_medium"
android:pathData="M40,840L480,80L920,840L40,840ZM178,760L782,760L480,240L178,760ZM480,720Q497,720 508.5,708.5Q520,697 520,680Q520,663 508.5,651.5Q497,640 480,640Q463,640 451.5,651.5Q440,663 440,680Q440,697 451.5,708.5Q463,720 480,720ZM440,600L520,600L520,400L440,400L440,600ZM480,500L480,500L480,500L480,500Z"/>
</vector>
\ No newline at end of file
diff --git a/res/layout/wifi_network_config.xml b/res/layout/wifi_network_config.xml
index dbd3e67..d3680b1 100644
--- a/res/layout/wifi_network_config.xml
+++ b/res/layout/wifi_network_config.xml
@@ -16,11 +16,13 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/l_wifidialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:paddingBottom="8dip">
+ android:paddingBottom="8dip"
+ android:theme="@style/Theme.AppCompat.DayNight">
<LinearLayout android:id="@+id/wep_warning_layout"
android:layout_width="match_parent"
@@ -50,30 +52,34 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/wifi_item">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@style/wifi_item_label"
- android:text="@string/wifi_ssid"
- android:textDirection="locale"/>
-
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
- <EditText android:id="@+id/ssid"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- style="@style/wifi_item_edit_content"
- android:hint="@string/wifi_ssid_hint"
- android:singleLine="true"
- android:inputType="textNoSuggestions"/>
+ <com.google.android.material.textfield.TextInputLayout
+ android:id="@+id/ssid_layout"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:hint="@string/wifi_ssid"
+ android:theme="@style/Theme.Settings"
+ android:textDirection="locale"
+ app:endIconMode="clear_text"
+ app:errorEnabled="true">
+
+ <com.google.android.material.textfield.TextInputEditText
+ android:id="@+id/ssid"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:inputType="textNoSuggestions"
+ android:singleLine="true"/>
+ </com.google.android.material.textfield.TextInputLayout>
<ImageButton
android:id="@+id/ssid_scanner_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="center"
android:minWidth="@dimen/min_tap_target_size"
android:minHeight="@dimen/min_tap_target_size"
android:background="?android:attr/selectableItemBackground"
diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml
index c767f04..212f1a6 100644
--- a/res/values-night/colors.xml
+++ b/res/values-night/colors.xml
@@ -55,9 +55,6 @@
<!-- Icon tint color for battery usage system icon -->
<color name="battery_usage_system_icon_color">@android:color/white</color>
- <!-- Power anomaly color for icons, button and text -->
- <color name="power_anomaly_app_warning_hint_color">#FDD663</color>
-
<!-- UDFPS colors -->
<color name="udfps_enroll_icon">#7DA7F1</color>
<color name="udfps_moving_target_fill">#475670</color>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 5de6222..e653c63 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1459,11 +1459,6 @@
<item>ic_battery_tips_warning_icon</item>
</string-array>
- <string-array name="battery_tips_card_colors" translatable="false">
- <item>color_accent_selector</item>
- <item>color_battery_anomaly_app_warning_selector</item>
- </string-array>
-
<!-- The following 4 arrays are for power anomaly tips card. Please keep them the same size. -->
<string-array name="power_anomaly_title_ids" translatable="false">
<item>battery_tips_settings_summary_brightness</item>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 7c4dd42..08818a9 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -168,9 +168,6 @@
<!-- Icon tint color for battery usage system icon -->
<color name="battery_usage_system_icon_color">?android:attr/textColorPrimary</color>
- <!-- Power anomaly color for icons, button -->
- <color name="power_anomaly_app_warning_hint_color">#D56E0C</color>
-
<!-- UDFPS colors -->
<!-- colorPrimaryGoogle light #1A73E8 (Blue600)-->
<color name="udfps_enroll_icon">#1A73E8</color>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 95b789da..9ded9ad 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -10798,7 +10798,7 @@
<string name="apps_summary"><xliff:g id="count" example="24">%1$d</xliff:g> apps installed</string>
<!-- Summary of storage usage [CHAR LIMIT=NONE] -->
- <string name="storage_summary"><xliff:g id="percentage" example="54%">%1$s</xliff:g> used - <xliff:g id="free_space" example="32GB">%2$s</xliff:g> free</string>
+ <string name="storage_summary"><xliff:g id="percentage" example="54%">%1$s</xliff:g> used - <xliff:g id="free_space_value" example="32">%2$s</xliff:g> <xliff:g id="free_space_units" example="GB">%3$s</xliff:g> free</string>
<!-- Summary for Display settings, explaining a few important settings under it [CHAR LIMIT=NONE]-->
<string name="display_dashboard_summary">Dark theme, font size, brightness</string>
@@ -14057,6 +14057,8 @@
<string name="audio_sharing_block_pairing_dialog_content">To pair a new device, turn off Audio Sharing first.</string>
<!-- Text for audio sharing turn off button [CHAR LIMIT=none]-->
<string name="audio_sharing_turn_off_button_label">Turn off</string>
+ <!-- Title for audio sharing notification to share audio with headset [CHAR LIMIT=none]-->
+ <string name="share_audio_notification_title">Share audio with <xliff:g example="My buds" id="device_name">%1$s</xliff:g></string>
<!-- Title for audio streams preference category [CHAR LIMIT=none]-->
<string name="audio_streams_category_title">Connect to a LE audio stream</string>
diff --git a/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml
index 4f7a494..ce71f54 100644
--- a/res/xml/mobile_network_settings.xml
+++ b/res/xml/mobile_network_settings.xml
@@ -204,7 +204,7 @@
<PreferenceCategory
android:key="telephony_satellite_settings_category_key"
- android:title="@string/satellite_setting_title"
+ android:title="@string/category_title_satellite_connectivity"
settings:controller="com.android.settings.network.telephony.SatelliteSettingsPreferenceCategoryController">
<com.android.settingslib.RestrictedPreference
diff --git a/res/xml/power_usage_advanced.xml b/res/xml/power_usage_advanced.xml
index 3258b7b..cc37625 100644
--- a/res/xml/power_usage_advanced.xml
+++ b/res/xml/power_usage_advanced.xml
@@ -21,18 +21,11 @@
android:title="@string/advanced_battery_title"
settings:keywords="@string/keywords_battery_usage">
- <PreferenceCategory
- android:key="battery_tips_category"
- android:layout="@layout/preference_category_no_label"
+ <com.android.settingslib.widget.BannerMessagePreference
+ android:key="battery_tips_card"
settings:controller=
"com.android.settings.fuelgauge.batteryusage.BatteryTipsController"
- settings:isPreferenceVisible="false">
-
- <com.android.settings.widget.TipCardPreference
- android:key="battery_tips_card"
- settings:isPreferenceVisible="false" />
-
- </PreferenceCategory>
+ settings:isPreferenceVisible="false" />
<com.android.settings.fuelgauge.batteryusage.BatteryHistoryPreference
android:key="battery_chart"
diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java
index f272c1d..77c39cd 100644
--- a/src/com/android/settings/SettingsPreferenceFragment.java
+++ b/src/com/android/settings/SettingsPreferenceFragment.java
@@ -50,12 +50,14 @@
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.flags.Flags;
+import com.android.settings.restriction.UserRestrictionBindingHelper;
import com.android.settings.support.actionbar.HelpResourceProvider;
import com.android.settings.widget.HighlightablePreferenceGroupAdapter;
import com.android.settings.widget.LoadingViewController;
import com.android.settingslib.CustomDialogPreferenceCompat;
import com.android.settingslib.CustomEditTextPreferenceCompat;
import com.android.settingslib.core.instrumentation.Instrumentable;
+import com.android.settingslib.preference.PreferenceScreenBindingHelper;
import com.android.settingslib.preference.PreferenceScreenCreator;
import com.android.settingslib.search.Indexable;
import com.android.settingslib.widget.LayoutPreference;
@@ -130,6 +132,8 @@
public HighlightablePreferenceGroupAdapter mAdapter;
private boolean mPreferenceHighlighted = false;
+ private @Nullable UserRestrictionBindingHelper mUserRestrictionBindingHelper;
+
@Override
public void onAttach(Context context) {
if (shouldSkipForInitialSUW() && !WizardManagerHelper.isDeviceProvisioned(getContext())) {
@@ -148,6 +152,14 @@
mPreferenceHighlighted = icicle.getBoolean(SAVE_HIGHLIGHTED_KEY);
}
HighlightablePreferenceGroupAdapter.adjustInitialExpandedChildCount(this /* host */);
+
+ if (isCatalystEnabled()) {
+ PreferenceScreenBindingHelper helper = getPreferenceScreenBindingHelper();
+ if (helper != null) {
+ mUserRestrictionBindingHelper = new UserRestrictionBindingHelper(requireContext(),
+ helper);
+ }
+ }
}
@Override
@@ -501,6 +513,15 @@
}
@Override
+ public void onDestroy() {
+ if (mUserRestrictionBindingHelper != null) {
+ mUserRestrictionBindingHelper.close();
+ mUserRestrictionBindingHelper = null;
+ }
+ super.onDestroy();
+ }
+
+ @Override
public void onDetach() {
if (isRemoving()) {
if (mDialogFragment != null) {
diff --git a/src/com/android/settings/accessibility/AccessibilityDialogUtils.java b/src/com/android/settings/accessibility/AccessibilityDialogUtils.java
index a1f59c8..c89b8d7 100644
--- a/src/com/android/settings/accessibility/AccessibilityDialogUtils.java
+++ b/src/com/android/settings/accessibility/AccessibilityDialogUtils.java
@@ -24,6 +24,7 @@
import android.view.View;
import android.widget.AbsListView;
import android.widget.AdapterView;
+import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ScrollView;
@@ -34,14 +35,15 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.Optional;
/**
* Utility class for creating the edit dialog.
*/
public class AccessibilityDialogUtils {
- private static final String TAG = "AccessibilityDialogUtils";
+ private static final String TAG = AccessibilityDialogUtils.class.getSimpleName();
- /** Denotes the dialog emuns for show dialog. */
+ /** Denotes the dialog enums for show dialog. */
@Retention(RetentionPolicy.SOURCE)
public @interface DialogEnums {
/**
@@ -89,6 +91,19 @@
* OPEN: Settings > Accessibility > Display size and text > Click 'Reset settings' button.
*/
int DIALOG_RESET_SETTINGS = 1009;
+
+ /**
+ * OPEN: Settings > Accessibility > Magnification > Magnification type.
+ */
+ int DIALOG_MAGNIFICATION_MODE = 1010;
+
+ /**
+ * Enable: Settings > Accessibility > Magnification > Magnification shortcut > Advanced >
+ * Triple tap.
+ * OPEN: Settings > Accessibility > Magnification > Magnification type > Magnify part of
+ * screen / Switch between full and partial screen > Save.
+ */
+ int DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING = 1011;
}
/**
@@ -118,17 +133,26 @@
* is clicked
* @return the {@link Dialog} with the given view
*/
- public static Dialog createCustomDialog(Context context, CharSequence dialogTitle,
- View customView, CharSequence positiveButtonText,
- DialogInterface.OnClickListener positiveListener, CharSequence negativeButtonText,
- DialogInterface.OnClickListener negativeListener) {
- final AlertDialog alertDialog = new AlertDialog.Builder(context)
- .setView(customView)
+ @NonNull
+ public static Dialog createCustomDialog(@NonNull Context context,
+ @NonNull CharSequence dialogTitle, @Nullable View customView,
+ @NonNull CharSequence positiveButtonText,
+ @Nullable DialogInterface.OnClickListener positiveListener,
+ @NonNull CharSequence negativeButtonText,
+ @Nullable DialogInterface.OnClickListener negativeListener) {
+ DialogInterface.OnClickListener doNothingListener =
+ (DialogInterface dialogInterface, int which) -> {};
+ final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context)
.setTitle(dialogTitle)
.setCancelable(true)
- .setPositiveButton(positiveButtonText, positiveListener)
- .setNegativeButton(negativeButtonText, negativeListener)
- .create();
+ .setPositiveButton(positiveButtonText,
+ Optional.ofNullable(positiveListener).orElse(doNothingListener))
+ .setNegativeButton(negativeButtonText,
+ Optional.ofNullable(negativeListener).orElse(doNothingListener));
+ if (customView != null) {
+ dialogBuilder.setView(customView);
+ }
+ final AlertDialog alertDialog = dialogBuilder.create();
if (customView instanceof ScrollView || customView instanceof AbsListView) {
setScrollIndicators(customView);
}
@@ -151,8 +175,7 @@
list.setId(android.R.id.list);
list.setDivider(/* divider= */ null);
list.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
- final ItemInfoArrayAdapter
- adapter = new ItemInfoArrayAdapter(context, itemInfoList);
+ final ListAdapter adapter = new ItemInfoArrayAdapter<>(context, itemInfoList);
list.setAdapter(adapter);
list.setOnItemClickListener(itemListener);
return list;
diff --git a/src/com/android/settings/accessibility/DialogHelper.java b/src/com/android/settings/accessibility/DialogHelper.java
new file mode 100644
index 0000000..6b86de5
--- /dev/null
+++ b/src/com/android/settings/accessibility/DialogHelper.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+/**
+ * The {@code DialogHelper} interface provides methods for displaying dialogs.
+ * It helps the dialog delegate to show the dialog, and will be injected to the dialog delegate.
+ */
+public interface DialogHelper {
+ /**
+ * Shows a dialog with the specified dialog ID.
+ *
+ * @param dialogId The ID of the dialog to display.
+ */
+ void showDialog(int dialogId);
+}
diff --git a/src/com/android/settings/accessibility/MagnificationModePreferenceController.java b/src/com/android/settings/accessibility/MagnificationModePreferenceController.java
index a8814ac..71ea4c2 100644
--- a/src/com/android/settings/accessibility/MagnificationModePreferenceController.java
+++ b/src/com/android/settings/accessibility/MagnificationModePreferenceController.java
@@ -37,11 +37,13 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import androidx.core.util.Preconditions;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.DialogCreatable;
import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.utils.AnnotationSpan;
@@ -57,33 +59,37 @@
DialogCreatable, LifecycleObserver, OnCreate, OnSaveInstanceState {
static final String PREF_KEY = "screen_magnification_mode";
- private static final int DIALOG_ID_BASE = 10;
- @VisibleForTesting
- static final int DIALOG_MAGNIFICATION_MODE = DIALOG_ID_BASE + 1;
- @VisibleForTesting
- static final int DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING = DIALOG_ID_BASE + 2;
- @VisibleForTesting
static final String EXTRA_MODE = "mode";
- private static final String TAG = "MagnificationModePreferenceController";
+ private static final String TAG = MagnificationModePreferenceController.class.getSimpleName();
+ @Nullable
private DialogHelper mDialogHelper;
// The magnification mode in the dialog.
@MagnificationMode
private int mModeCache = MagnificationMode.NONE;
+ @Nullable
private Preference mModePreference;
+ @Nullable
private ShortcutPreference mLinkPreference;
@VisibleForTesting
+ @Nullable
ListView mMagnificationModesListView;
private final List<MagnificationModeInfo> mModeInfos = new ArrayList<>();
- public MagnificationModePreferenceController(Context context, String preferenceKey) {
+ public MagnificationModePreferenceController(@NonNull Context context,
+ @NonNull String preferenceKey) {
super(context, preferenceKey);
initModeInfos();
}
+
+ public void setDialogHelper(@NonNull DialogHelper dialogHelper) {
+ mDialogHelper = dialogHelper;
+ }
+
private void initModeInfos() {
mModeInfos.add(new MagnificationModeInfo(mContext.getText(
R.string.accessibility_magnification_mode_dialog_option_full_screen), null,
@@ -103,6 +109,7 @@
return AVAILABLE;
}
+ @NonNull
@Override
public CharSequence getSummary() {
final int capabilities = MagnificationCapabilities.getCapabilities(mContext);
@@ -110,99 +117,98 @@
}
@Override
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(@Nullable Bundle savedInstanceState) {
if (savedInstanceState != null) {
mModeCache = savedInstanceState.getInt(EXTRA_MODE, MagnificationMode.NONE);
}
}
@Override
- public void displayPreference(PreferenceScreen screen) {
+ public void displayPreference(@NonNull PreferenceScreen screen) {
super.displayPreference(screen);
mModePreference = screen.findPreference(getPreferenceKey());
mLinkPreference = screen.findPreference(
ToggleFeaturePreferenceFragment.KEY_SHORTCUT_PREFERENCE);
- mModePreference.setOnPreferenceClickListener(preference -> {
+ Preconditions.checkNotNull(mModePreference).setOnPreferenceClickListener(preference -> {
mModeCache = MagnificationCapabilities.getCapabilities(mContext);
- mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE);
+ Preconditions.checkNotNull(mDialogHelper).showDialog(
+ DialogEnums.DIALOG_MAGNIFICATION_MODE);
return true;
});
}
@Override
- public void onSaveInstanceState(Bundle outState) {
+ public void onSaveInstanceState(@NonNull Bundle outState) {
outState.putInt(EXTRA_MODE, mModeCache);
}
- /**
- * Sets {@link DialogHelper} used to show the dialog.
- */
- public void setDialogHelper(DialogHelper dialogHelper) {
- mDialogHelper = dialogHelper;
- mDialogHelper.setDialogDelegate(this);
- }
-
+ @NonNull
@Override
public Dialog onCreateDialog(int dialogId) {
- switch (dialogId) {
- case DIALOG_MAGNIFICATION_MODE:
- return createMagnificationModeDialog();
-
- case DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING:
- return createMagnificationTripleTapWarningDialog();
- }
- return null;
+ return switch (dialogId) {
+ case DialogEnums.DIALOG_MAGNIFICATION_MODE -> createMagnificationModeDialog();
+ case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING ->
+ createMagnificationTripleTapWarningDialog();
+ default -> throw new IllegalArgumentException(
+ "This only handles magnification mode and triple tap warning dialog");
+ };
}
@Override
public int getDialogMetricsCategory(int dialogId) {
- switch (dialogId) {
- case DIALOG_MAGNIFICATION_MODE:
- return SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY;
- case DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING:
- return SettingsEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING;
- default:
- return 0;
- }
+ return switch (dialogId) {
+ case DialogEnums.DIALOG_MAGNIFICATION_MODE ->
+ SettingsEnums.DIALOG_MAGNIFICATION_CAPABILITY;
+ case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING ->
+ SettingsEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING;
+ default -> 0;
+ };
}
+ @NonNull
+ private ListView getMagnificationModesListView() {
+ return Preconditions.checkNotNull(mMagnificationModesListView);
+ }
+
+ @NonNull
private Dialog createMagnificationModeDialog() {
mMagnificationModesListView = AccessibilityDialogUtils.createSingleChoiceListView(
mContext, mModeInfos, this::onMagnificationModeSelected);
final View headerView = LayoutInflater.from(mContext).inflate(
- R.layout.accessibility_magnification_mode_header, mMagnificationModesListView,
- false);
- mMagnificationModesListView.addHeaderView(headerView, /* data= */ null, /* isSelectable= */
- false);
+ R.layout.accessibility_magnification_mode_header,
+ getMagnificationModesListView(), /* attachToRoot= */false);
+ getMagnificationModesListView().addHeaderView(headerView, /* data= */null,
+ /* isSelectable= */false);
- mMagnificationModesListView.setItemChecked(computeSelectionIndex(), true);
+ getMagnificationModesListView().setItemChecked(computeSelectionIndex(), /* value= */true);
final CharSequence title = mContext.getString(
R.string.accessibility_magnification_mode_dialog_title);
final CharSequence positiveBtnText = mContext.getString(R.string.save);
final CharSequence negativeBtnText = mContext.getString(R.string.cancel);
return AccessibilityDialogUtils.createCustomDialog(mContext, title,
- mMagnificationModesListView,
- positiveBtnText, this::onMagnificationModeDialogPositiveButtonClicked,
- negativeBtnText, /* negativeListener= */ null);
+ getMagnificationModesListView(), positiveBtnText,
+ this::onMagnificationModeDialogPositiveButtonClicked,
+ negativeBtnText, /* negativeListener= */null);
}
@VisibleForTesting
- void onMagnificationModeDialogPositiveButtonClicked(DialogInterface dialogInterface,
+ void onMagnificationModeDialogPositiveButtonClicked(@NonNull DialogInterface dialogInterface,
int which) {
- final int selectedIndex = mMagnificationModesListView.getCheckedItemPosition();
+ final int selectedIndex = getMagnificationModesListView().getCheckedItemPosition();
if (selectedIndex == AdapterView.INVALID_POSITION) {
- Log.w(TAG, "invalid index");
+ Log.w(TAG, "Selected positive button with INVALID_POSITION index");
return;
}
- mModeCache = ((MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
- selectedIndex)).mMagnificationMode;
+ mModeCache = ((MagnificationModeInfo) getMagnificationModesListView().getItemAtPosition(
+ selectedIndex)).mMagnificationMode;
// Do not save mode until user clicks positive button in triple tap warning dialog.
if (isTripleTapEnabled(mContext) && mModeCache != MagnificationMode.FULLSCREEN) {
- mDialogHelper.showDialog(DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
+ Preconditions.checkNotNull(mDialogHelper).showDialog(
+ DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
} else { // Save mode (capabilities) value, don't need to show dialog to confirm.
updateCapabilitiesAndSummary(mModeCache);
}
@@ -211,15 +217,14 @@
private void updateCapabilitiesAndSummary(@MagnificationMode int mode) {
mModeCache = mode;
MagnificationCapabilities.setCapabilities(mContext, mModeCache);
- mModePreference.setSummary(
+ Preconditions.checkNotNull(mModePreference).setSummary(
MagnificationCapabilities.getSummary(mContext, mModeCache));
}
- private void onMagnificationModeSelected(AdapterView<?> parent, View view, int position,
- long id) {
+ private void onMagnificationModeSelected(@NonNull AdapterView<?> parent, @NonNull View view,
+ int position, long id) {
final MagnificationModeInfo modeInfo =
- (MagnificationModeInfo) mMagnificationModesListView.getItemAtPosition(
- position);
+ (MagnificationModeInfo) getMagnificationModesListView().getItemAtPosition(position);
if (modeInfo.mMagnificationMode == mModeCache) {
return;
}
@@ -230,20 +235,22 @@
final int modesSize = mModeInfos.size();
for (int i = 0; i < modesSize; i++) {
if (mModeInfos.get(i).mMagnificationMode == mModeCache) {
- return i + mMagnificationModesListView.getHeaderViewsCount();
+ return i + getMagnificationModesListView().getHeaderViewsCount();
}
}
- Log.w(TAG, "computeSelectionIndex failed");
+ Log.w(TAG, "Can not find matching mode in mModeInfos");
return 0;
}
@VisibleForTesting
- static boolean isTripleTapEnabled(Context context) {
+ static boolean isTripleTapEnabled(@NonNull Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, OFF) == ON;
}
+ @NonNull
private Dialog createMagnificationTripleTapWarningDialog() {
+ @SuppressWarnings({"InflateParams"})
final View contentView = LayoutInflater.from(mContext).inflate(
R.layout.magnification_triple_tap_warning_dialog, /* root= */ null);
final CharSequence title = mContext.getString(
@@ -263,12 +270,13 @@
return dialog;
}
- private void updateLinkInTripleTapWarningDialog(Dialog dialog, View contentView) {
+ private void updateLinkInTripleTapWarningDialog(@NonNull Dialog dialog,
+ @NonNull View contentView) {
final TextView messageView = contentView.findViewById(R.id.message);
// TODO(b/225682559): Need to remove performClick() after refactoring accessibility dialog.
final View.OnClickListener linkListener = view -> {
updateCapabilitiesAndSummary(mModeCache);
- mLinkPreference.performClick();
+ Preconditions.checkNotNull(mLinkPreference).performClick();
dialog.dismiss();
};
final AnnotationSpan.LinkInfo linkInfo = new AnnotationSpan.LinkInfo(
@@ -285,25 +293,18 @@
@VisibleForTesting
void onMagnificationTripleTapWarningDialogNegativeButtonClicked(
- DialogInterface dialogInterface, int which) {
+ @NonNull DialogInterface dialogInterface, int which) {
mModeCache = MagnificationCapabilities.getCapabilities(mContext);
- mDialogHelper.showDialog(DIALOG_MAGNIFICATION_MODE);
+ Preconditions.checkNotNull(mDialogHelper).showDialog(
+ DialogEnums.DIALOG_MAGNIFICATION_MODE);
}
@VisibleForTesting
void onMagnificationTripleTapWarningDialogPositiveButtonClicked(
- DialogInterface dialogInterface, int which) {
+ @NonNull DialogInterface dialogInterface, int which) {
updateCapabilitiesAndSummary(mModeCache);
}
- /**
- * An interface to help the delegate to show the dialog. It will be injected to the delegate.
- */
- interface DialogHelper extends DialogCreatable {
- void showDialog(int dialogId);
- void setDialogDelegate(DialogCreatable delegate);
- }
-
@VisibleForTesting
static class MagnificationModeInfo extends ItemInfoArrayAdapter.ItemInfo {
@MagnificationMode
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
index 5ecdf67..e0da6f4 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -19,7 +19,6 @@
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_COMPONENT_NAME;
import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME;
import static com.android.internal.accessibility.common.ShortcutConstants.UserShortcutType.DEFAULT;
-import static com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
import static com.android.settings.accessibility.AccessibilityUtil.getShortcutSummaryList;
@@ -42,8 +41,10 @@
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
+import androidx.core.util.Preconditions;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.SwitchPreferenceCompat;
@@ -53,6 +54,7 @@
import com.android.server.accessibility.Flags;
import com.android.settings.DialogCreatable;
import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
import com.android.settings.accessibility.shortcuts.EditShortcutsPreferenceFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -74,10 +76,10 @@
*/
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class ToggleScreenMagnificationPreferenceFragment extends
- ToggleFeaturePreferenceFragment implements
- MagnificationModePreferenceController.DialogHelper {
+ ToggleFeaturePreferenceFragment implements DialogHelper {
- private static final String TAG = "ToggleScreenMagnificationPreferenceFragment";
+ private static final String TAG =
+ ToggleScreenMagnificationPreferenceFragment.class.getSimpleName();
@VisibleForTesting
static final String KEY_MAGNIFICATION_SHORTCUT_PREFERENCE = "magnification_shortcut_preference";
private static final char COMPONENT_NAME_SEPARATOR = ':';
@@ -86,23 +88,30 @@
// TODO(b/147021230): Move duplicated functions with android/internal/accessibility into util.
private TouchExplorationStateChangeListener mTouchExplorationStateChangeListener;
- private DialogCreatable mDialogDelegate;
+ @Nullable
+ private DialogCreatable mMagnificationModeDialogDelegate;
@Nullable
MagnificationOneFingerPanningPreferenceController mOneFingerPanningPreferenceController;
private boolean mInSetupWizard;
+ @VisibleForTesting
+ public void setMagnificationModeDialogDelegate(@NonNull DialogCreatable delegate) {
+ mMagnificationModeDialogDelegate = delegate;
+ }
+
@Override
- public void onCreate(Bundle savedInstanceState) {
+ public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().setTitle(R.string.accessibility_screen_magnification_title);
mInSetupWizard = WizardManagerHelper.isAnySetupWizard(getIntent());
}
+ @NonNull
@Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
+ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+ @NonNull Bundle savedInstanceState) {
mFeatureName = getString(R.string.accessibility_screen_magnification_title);
mImageUri = new Uri.Builder().scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
.authority(getPrefContext().getPackageName())
@@ -161,15 +170,14 @@
super.onPause();
}
+ @NonNull
@Override
public Dialog onCreateDialog(int dialogId) {
- if (mDialogDelegate != null) {
- mDialog = mDialogDelegate.onCreateDialog(dialogId);
- if (mDialog != null) {
- return mDialog;
- }
- }
switch (dialogId) {
+ case DialogEnums.DIALOG_MAGNIFICATION_MODE:
+ case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING:
+ return Preconditions.checkNotNull(mMagnificationModeDialogDelegate)
+ .onCreateDialog(dialogId);
case DialogEnums.GESTURE_NAVIGATION_TUTORIAL:
return AccessibilityShortcutsTutorial
.showAccessibilityGestureTutorialDialog(getPrefContext());
@@ -238,9 +246,10 @@
generalCategory.addPreference(mSettingsPreference);
final MagnificationModePreferenceController magnificationModePreferenceController =
- new MagnificationModePreferenceController(getContext(),
+ new MagnificationModePreferenceController(Preconditions.checkNotNull(getContext()),
MagnificationModePreferenceController.PREF_KEY);
- magnificationModePreferenceController.setDialogHelper(this);
+ magnificationModePreferenceController.setDialogHelper(/* dialogHelper= */this);
+ mMagnificationModeDialogDelegate = magnificationModePreferenceController;
getSettingsLifecycle().addObserver(magnificationModePreferenceController);
magnificationModePreferenceController.displayPreference(getPreferenceScreen());
addPreferenceController(magnificationModePreferenceController);
@@ -389,11 +398,6 @@
}
@Override
- public void setDialogDelegate(DialogCreatable delegate) {
- mDialogDelegate = delegate;
- }
-
- @Override
protected void registerKeysToObserverCallback(
AccessibilitySettingsContentObserver contentObserver) {
super.registerKeysToObserverCallback(contentObserver);
@@ -470,14 +474,11 @@
@Override
public int getDialogMetricsCategory(int dialogId) {
- if (mDialogDelegate != null) {
- final int category = mDialogDelegate.getDialogMetricsCategory(dialogId);
- if (category != 0) {
- return category;
- }
- }
-
switch (dialogId) {
+ case DialogEnums.DIALOG_MAGNIFICATION_MODE:
+ case DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING:
+ return Preconditions.checkNotNull(mMagnificationModeDialogDelegate)
+ .getDialogMetricsCategory(dialogId);
case DialogEnums.GESTURE_NAVIGATION_TUTORIAL:
return SettingsEnums.DIALOG_TOGGLE_SCREEN_MAGNIFICATION_GESTURE_NAVIGATION;
case DialogEnums.ACCESSIBILITY_BUTTON_TUTORIAL:
@@ -514,7 +515,7 @@
}
@Override
- public void onToggleClicked(ShortcutPreference preference) {
+ public void onToggleClicked(@NonNull ShortcutPreference preference) {
final int shortcutTypes = getUserPreferredShortcutTypes();
getPrefContext().getSystemService(AccessibilityManager.class).enableShortcutsForTargets(
preference.isChecked(), shortcutTypes,
@@ -527,7 +528,7 @@
}
@Override
- public void onSettingsClicked(ShortcutPreference preference) {
+ public void onSettingsClicked(@NonNull ShortcutPreference preference) {
EditShortcutsPreferenceFragment.showEditShortcutScreen(
requireContext(),
getMetricsCategory(),
@@ -581,7 +582,8 @@
*
* @param context The current context.
*/
- public static CharSequence getServiceSummary(Context context) {
+ @NonNull
+ public static CharSequence getServiceSummary(@NonNull Context context) {
// Get the user shortcut type from settings provider.
final int userShortcutType = ShortcutUtils.getEnabledShortcutTypes(
context, MAGNIFICATION_CONTROLLER_NAME);
@@ -604,8 +606,9 @@
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
// LINT.IfChange(search_data)
+ @NonNull
@Override
- public List<SearchIndexableRaw> getRawDataToIndex(Context context,
+ public List<SearchIndexableRaw> getRawDataToIndex(@NonNull Context context,
boolean enabled) {
final List<SearchIndexableRaw> rawData =
super.getRawDataToIndex(context, enabled);
@@ -628,8 +631,9 @@
return rawData;
}
+ @NonNull
@Override
- public List<String> getNonIndexableKeys(Context context) {
+ public List<String> getNonIndexableKeys(@NonNull Context context) {
final List<String> niks = super.getNonIndexableKeys(context);
if (!com.android.settings.accessibility.Flags.fixA11ySettingsSearch()) {
diff --git a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
index 1ab86f9..1598e10 100644
--- a/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
+++ b/src/com/android/settings/activityembedding/ActivityEmbeddingRulesController.java
@@ -52,6 +52,7 @@
import com.android.settings.privatespace.delete.PrivateSpaceDeleteActivity;
import com.android.settings.remoteauth.RemoteAuthActivity;
import com.android.settings.remoteauth.RemoteAuthActivityInternal;
+import com.android.settingslib.users.CreateUserActivity;
import java.util.Collection;
import java.util.HashSet;
@@ -278,6 +279,10 @@
String action = mContext.getString(R.string.config_avatar_picker_action);
addActivityFilter(activityFilters, new Intent(action));
+ if (android.multiuser.Flags.placeAddUserDialogWithinActivity()) {
+ addActivityFilter(activityFilters, CreateUserActivity.class);
+ }
+
ActivityRule activityRule = new ActivityRule.Builder(activityFilters).setAlwaysExpand(true)
.build();
mRuleController.addRule(activityRule);
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java b/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
index 86f0314..f0bed94 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBase.java
@@ -46,7 +46,6 @@
import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.HearingAidStatsLogUtils;
-import com.android.settingslib.flags.Flags;
import com.android.settingslib.utils.ThreadUtils;
import com.google.common.collect.ImmutableList;
@@ -63,7 +62,6 @@
public abstract class BluetoothDevicePairingDetailBase extends DeviceListPreferenceFragment {
private static final long AUTO_DISMISS_TIME_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(15);
private static final int AUTO_DISMISS_MESSAGE_ID = 1001;
- private static final int AUTO_FINISH_MESSAGE_ID = 1002;
private static final ImmutableList<Integer> AUDIO_SHARING_PROFILES = ImmutableList.of(
BluetoothProfile.LE_AUDIO,
BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT, BluetoothProfile.VOLUME_CONTROL);
@@ -91,8 +89,8 @@
// onDeviceBondStateChanged(BOND_BONDED), BluetoothDevicePreference's summary has already
// change from "Pairing..." to empty since it listens to metadata changes happens earlier.
//
- // In pairing flow during audio sharing, we have to wait on this page till the device is
- // connected to check the device type and handle extra logic for audio sharing.
+ // In share then pair flow, we have to wait on this page till the device is connected to check
+ // the device type and handle extra logic for audio sharing.
// The BluetoothDevicePreference summary will be blank for seconds between "Pairing..." and
// "Connecting..." To help users better understand the process, we listen to metadata change
// as well and show a progress dialog with "Connecting to ...." once BluetoothDevice.getState()
@@ -103,11 +101,10 @@
public void onMetadataChanged(@NonNull BluetoothDevice device, int key,
@Nullable byte[] value) {
Log.d(getLogTag(), "onMetadataChanged device = " + device + ", key = " + key);
- if ((mShouldTriggerShareThenPairFlow || shouldSetTempBondMetadata())
- && mProgressDialog == null
+ if (mShouldTriggerShareThenPairFlow && mProgressDialog == null
&& device.getBondState() == BluetoothDevice.BOND_BONDED
&& mSelectedList.contains(device)) {
- handleDeviceBondedInAudioSharing(device);
+ handleShareThenPair(device);
// Once device is bonded, remove the listener
removeOnMetadataChangedListener(device);
}
@@ -181,12 +178,11 @@
@Override
public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
- boolean shouldSetTempBond = shouldSetTempBondMetadata();
if (bondState == BluetoothDevice.BOND_BONDED) {
- if (cachedDevice != null && (mShouldTriggerShareThenPairFlow || shouldSetTempBond)) {
+ if (cachedDevice != null && mShouldTriggerShareThenPairFlow) {
BluetoothDevice device = cachedDevice.getDevice();
if (device != null && mSelectedList.contains(device)) {
- handleDeviceBondedInAudioSharing(device);
+ handleShareThenPair(device);
removeOnMetadataChangedListener(device);
return;
}
@@ -195,7 +191,7 @@
finish();
return;
} else if (bondState == BluetoothDevice.BOND_BONDING) {
- if ((mShouldTriggerShareThenPairFlow || shouldSetTempBond) && cachedDevice != null) {
+ if (mShouldTriggerShareThenPairFlow && cachedDevice != null) {
BluetoothDevice device = cachedDevice.getDevice();
if (device != null && mSelectedList.contains(device)) {
addOnMetadataChangedListener(device);
@@ -208,7 +204,7 @@
pageId);
HearingAidStatsLogUtils.setBondEntryForDevice(bondEntry, cachedDevice);
} else if (bondState == BluetoothDevice.BOND_NONE) {
- if ((mShouldTriggerShareThenPairFlow || shouldSetTempBond) && cachedDevice != null) {
+ if (mShouldTriggerShareThenPairFlow && cachedDevice != null) {
BluetoothDevice device = cachedDevice.getDevice();
if (device != null && mSelectedList.contains(device)) {
removeOnMetadataChangedListener(device);
@@ -240,22 +236,15 @@
&& mSelectedList.contains(device)) {
var unused = ThreadUtils.postOnBackgroundThread(() -> {
if (BluetoothUtils.isAudioSharingUIAvailable(getContext())) {
- if ((mShouldTriggerShareThenPairFlow || shouldSetTempBondMetadata())
+ if (mShouldTriggerShareThenPairFlow
&& state == BluetoothAdapter.STATE_CONNECTED
&& device.equals(mJustBonded)
&& AUDIO_SHARING_PROFILES.contains(bluetoothProfile)
&& isReadyForAudioSharing(cachedDevice, bluetoothProfile)) {
Log.d(getLogTag(), "onProfileConnectionStateChanged, lea eligible");
dismissConnectingDialog();
- BluetoothUtils.setTemporaryBondMetadata(device);
- if (mShouldTriggerShareThenPairFlow) {
- mHandler.removeMessages(AUTO_DISMISS_MESSAGE_ID);
- postOnMainThread(() ->
- finishFragmentWithResultForAudioSharing(device));
- } else {
- mHandler.removeMessages(AUTO_FINISH_MESSAGE_ID);
- postOnMainThread(() -> finish());
- }
+ mHandler.removeMessages(AUTO_DISMISS_MESSAGE_ID);
+ postOnMainThread(() -> finishFragmentWithResultForAudioSharing(device));
}
} else {
postOnMainThread(() -> finish());
@@ -341,16 +330,6 @@
return false;
}
- private boolean shouldSetTempBondMetadata() {
- return Flags.enableTemporaryBondDevicesUi()
- && BluetoothUtils.isAudioSharingUIAvailable(getContext())
- && BluetoothUtils.isBroadcasting(mLocalManager)
- && mLocalManager != null
- && mLocalManager.getCachedDeviceManager() != null
- && mLocalManager.getProfileManager().getLeAudioBroadcastAssistantProfile() != null
- && !Utils.shouldBlockPairingInAudioSharing(mLocalManager);
- }
-
private boolean isReadyForAudioSharing(@NonNull CachedBluetoothDevice cachedDevice,
int justConnectedProfile) {
for (int profile : AUDIO_SHARING_PROFILES) {
@@ -405,10 +384,10 @@
});
}
- private void handleDeviceBondedInAudioSharing(@Nullable BluetoothDevice device) {
+ private void handleShareThenPair(@Nullable BluetoothDevice device) {
var unused = ThreadUtils.postOnBackgroundThread(() -> {
if (mJustBonded != null) {
- Log.d(getLogTag(), "Skip handleDeviceBondedInAudioSharing, already done");
+ Log.d(getLogTag(), "Skip handleShareThenPair, already done");
return;
}
mJustBonded = device;
@@ -417,38 +396,21 @@
String deviceName = TextUtils.isEmpty(aliasName) ? device.getAddress()
: aliasName;
showConnectingDialog(deviceName);
- if (mShouldTriggerShareThenPairFlow) {
- // For share then pair flow, we have strong signal that users wish to pair new
- // device to join sharing.
- // So we wait for AUTO_DISMISS_TIME_THRESHOLD_MS, if we find that the bonded device
- // is lea in onProfileConnectionStateChanged, we finish the activity, set the device
- // as temp bond and auto add source; otherwise, show dialog to notify that the
- // device is incompatible for audio sharing.
- if (!mHandler.hasMessages(AUTO_DISMISS_MESSAGE_ID)) {
- mHandler.postDelayed(() ->
- postOnMainThread(
- () -> {
- Log.d(getLogTag(),
- "Show incompatible dialog when timeout");
- dismissConnectingDialog();
- AudioSharingIncompatibleDialogFragment.show(this,
- deviceName,
- () -> finish());
- }), AUTO_DISMISS_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS);
- }
- } else {
- // For other pairing request during audio sharing with sinks < 2, we wait for
- // AUTO_DISMISS_TIME_THRESHOLD_MS, if we find that the bonded device is lea in
- // onProfileConnectionStateChanged, we finish the activity and set the device as
- // temp bond; otherwise, we just finish the activity.
- if (!mHandler.hasMessages(AUTO_FINISH_MESSAGE_ID)) {
- mHandler.postDelayed(() ->
- postOnMainThread(
- () -> {
- Log.d(getLogTag(), "Finish activity when timeout");
- finish();
- }), AUTO_FINISH_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS);
- }
+ // For share then pair flow, we have strong signal that users wish to pair new
+ // device to join sharing.
+ // So we wait for AUTO_DISMISS_TIME_THRESHOLD_MS, if we find that the bonded device
+ // is lea in onProfileConnectionStateChanged, we finish the activity, set the device
+ // as temp bond and auto add source; otherwise, show dialog to notify that the
+ // device is incompatible for audio sharing.
+ if (!mHandler.hasMessages(AUTO_DISMISS_MESSAGE_ID)) {
+ mHandler.postDelayed(() ->
+ postOnMainThread(
+ () -> {
+ Log.d(getLogTag(), "Show incompatible dialog when timeout");
+ dismissConnectingDialog();
+ AudioSharingIncompatibleDialogFragment.show(this, deviceName,
+ () -> finish());
+ }), AUTO_DISMISS_MESSAGE_ID, AUTO_DISMISS_TIME_THRESHOLD_MS);
}
});
}
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java
index 740fb35..a7c7984 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiver.java
@@ -16,17 +16,26 @@
package com.android.settings.connecteddevice.audiosharing;
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE;
+
+import android.Manifest;
+import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.settings.SettingsEnums;
+import android.bluetooth.BluetoothCsipSetCoordinator;
+import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.Bundle;
+import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import com.android.settings.R;
@@ -37,18 +46,30 @@
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Map;
+
public class AudioSharingReceiver extends BroadcastReceiver {
private static final String TAG = "AudioSharingReceiver";
private static final String ACTION_LE_AUDIO_SHARING_SETTINGS =
"com.android.settings.BLUETOOTH_AUDIO_SHARING_SETTINGS";
private static final String ACTION_LE_AUDIO_SHARING_STOP =
"com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STOP";
+ private static final String ACTION_LE_AUDIO_SHARING_ADD_SOURCE =
+ "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_ADD_SOURCE";
+ private static final String ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF =
+ "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_CANCEL_NOTIF";
+ private static final String EXTRA_NOTIF_ID = "NOTIF_ID";
private static final String CHANNEL_ID = "bluetooth_notification_channel";
- private static final int NOTIFICATION_ID =
+ private static final int AUDIO_SHARING_NOTIFICATION_ID =
com.android.settingslib.R.drawable.ic_bt_le_audio_sharing;
+ private static final int ADD_SOURCE_NOTIFICATION_ID = R.string.share_audio_notification_title;
+ private static final int NOTIF_AUTO_DISMISS_MILLIS = 300000; //5mins
@Override
- public void onReceive(Context context, Intent intent) {
+ public void onReceive(@NonNull Context context, @NonNull Intent intent) {
String action = intent.getAction();
if (action == null) {
Log.w(TAG, "Received unexpected intent with null action.");
@@ -74,10 +95,12 @@
// isLeAudioBroadcastSourceSupported() and BluetoothAdapter#
// isLeAudioBroadcastAssistantSupported() always return FEATURE_SUPPORTED
// or FEATURE_NOT_SUPPORTED when BT and BLE off
- cancelSharingNotification(context);
+ cancelSharingNotification(context, AUDIO_SHARING_NOTIFICATION_ID);
metricsFeatureProvider.action(
context, SettingsEnums.ACTION_CANCEL_AUDIO_SHARING_NOTIFICATION,
LocalBluetoothLeBroadcast.ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
+ cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+ // TODO: add metric
} else {
Log.w(
TAG,
@@ -99,27 +122,92 @@
// isLeAudioBroadcastSourceSupported() and BluetoothAdapter#
// isLeAudioBroadcastAssistantSupported() always return FEATURE_SUPPORTED
// or FEATURE_NOT_SUPPORTED when BT and BLE off
- cancelSharingNotification(context);
+ cancelSharingNotification(context, AUDIO_SHARING_NOTIFICATION_ID);
metricsFeatureProvider.action(
context, SettingsEnums.ACTION_CANCEL_AUDIO_SHARING_NOTIFICATION,
ACTION_LE_AUDIO_SHARING_STOP);
+ cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+ break;
+ case LocalBluetoothLeBroadcast.ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED:
+ if (!BluetoothUtils.isAudioSharingUIAvailable(context)) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED, feature disabled.");
+ return;
+ }
+ BluetoothDevice device = intent.getParcelableExtra(EXTRA_BLUETOOTH_DEVICE,
+ BluetoothDevice.class);
+ if (device == null) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED, null device");
+ return;
+ }
+ if (isAppInForeground(context)) {
+ // TODO: show dialog
+ Log.d(TAG, "App in foreground, show share audio dialog");
+ } else {
+ Log.d(TAG, "App not in foreground, show share audio notification");
+ showAddSourceNotification(context, device);
+ }
+ break;
+ case ACTION_LE_AUDIO_SHARING_ADD_SOURCE:
+ if (!BluetoothUtils.isAudioSharingUIAvailable(context)) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, feature disabled.");
+ cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+ return;
+ }
+ BluetoothDevice sink = intent.getParcelableExtra(EXTRA_BLUETOOTH_DEVICE,
+ BluetoothDevice.class);
+ if (sink == null) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, null device");
+ cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+ return;
+ }
+ LocalBluetoothManager manager = Utils.getLocalBtManager(context);
+ boolean isBroadcasting = BluetoothUtils.isBroadcasting(manager);
+ if (!isBroadcasting) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, not broadcasting");
+ cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+ return;
+ }
+ Map<Integer, List<BluetoothDevice>> groupedDevices =
+ AudioSharingUtils.fetchConnectedDevicesByGroupId(manager);
+ int groupId = groupedDevices.entrySet().stream().filter(
+ entry -> entry.getValue().contains(sink)).findFirst().map(
+ Map.Entry::getKey).orElse(BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+ if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, no valid group id");
+ cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+ return;
+ }
+ List<BluetoothDevice> sinksToAdd = groupedDevices.getOrDefault(groupId,
+ ImmutableList.of()).stream().filter(
+ d -> !BluetoothUtils.hasConnectedBroadcastSourceForBtDevice(d,
+ manager)).toList();
+ if (sinksToAdd.isEmpty()) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, already has source");
+ } else if (groupedDevices.entrySet().stream().filter(
+ entry -> entry.getKey() != groupId && entry.getValue().stream().anyMatch(
+ d -> BluetoothUtils.hasConnectedBroadcastSourceForBtDevice(d,
+ manager))).toList().size() >= 2) {
+ Log.d(TAG, "Skip ACTION_LE_AUDIO_SHARING_ADD_SOURCE, already 2 sinks");
+ } else {
+ AudioSharingUtils.addSourceToTargetSinks(sinksToAdd, manager);
+ }
+ cancelSharingNotification(context, ADD_SOURCE_NOTIFICATION_ID);
+ break;
+ case ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF:
+ int notifId = intent.getIntExtra(EXTRA_NOTIF_ID, -1);
+ if (notifId != -1) {
+ cancelSharingNotification(context, notifId);
+ }
break;
default:
Log.w(TAG, "Received unexpected intent " + intent.getAction());
}
}
- private void showSharingNotification(Context context) {
+ private void showSharingNotification(@NonNull Context context) {
NotificationManager nm = context.getSystemService(NotificationManager.class);
- if (nm.getNotificationChannel(CHANNEL_ID) == null) {
- Log.d(TAG, "Create bluetooth notification channel");
- NotificationChannel notificationChannel =
- new NotificationChannel(
- CHANNEL_ID,
- context.getString(com.android.settings.R.string.bluetooth),
- NotificationManager.IMPORTANCE_HIGH);
- nm.createNotificationChannel(notificationChannel);
- }
+ if (nm == null) return;
+ createNotificationChannelIfNeeded(nm, context);
Intent stopIntent =
new Intent(ACTION_LE_AUDIO_SHARING_STOP).setPackage(context.getPackageName());
PendingIntent stopPendingIntent =
@@ -174,11 +262,110 @@
.addAction(stopAction)
.addAction(settingsAction)
.addExtras(extras);
- nm.notify(NOTIFICATION_ID, builder.build());
+ nm.notify(AUDIO_SHARING_NOTIFICATION_ID, builder.build());
}
- private void cancelSharingNotification(Context context) {
+ private void showAddSourceNotification(@NonNull Context context,
+ @NonNull BluetoothDevice device) {
NotificationManager nm = context.getSystemService(NotificationManager.class);
- nm.cancel(NOTIFICATION_ID);
+ if (nm == null) return;
+ createNotificationChannelIfNeeded(nm, context);
+ Intent addSourceIntent =
+ new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE).setPackage(context.getPackageName())
+ .putExtra(EXTRA_BLUETOOTH_DEVICE, device);
+ PendingIntent addSourcePendingIntent =
+ PendingIntent.getBroadcast(
+ context,
+ R.string.audio_sharing_share_button_label,
+ addSourceIntent,
+ PendingIntent.FLAG_IMMUTABLE);
+ NotificationCompat.Action addSourceAction =
+ new NotificationCompat.Action.Builder(
+ 0,
+ context.getString(R.string.audio_sharing_share_button_label),
+ addSourcePendingIntent)
+ .build();
+ Intent cancelIntent = new Intent(ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF).setPackage(
+ context.getPackageName())
+ .putExtra(EXTRA_NOTIF_ID, ADD_SOURCE_NOTIFICATION_ID);
+ PendingIntent cancelPendingIntent =
+ PendingIntent.getBroadcast(
+ context,
+ R.string.cancel,
+ cancelIntent,
+ PendingIntent.FLAG_IMMUTABLE);
+ NotificationCompat.Action cancelAction =
+ new NotificationCompat.Action.Builder(
+ 0,
+ context.getString(R.string.cancel),
+ cancelPendingIntent)
+ .build();
+ final Bundle extras = new Bundle();
+ extras.putString(
+ Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ context.getString(R.string.audio_sharing_title));
+ String deviceName = device.getAlias();
+ if (TextUtils.isEmpty(deviceName)) {
+ deviceName = device.getAddress();
+ }
+ NotificationCompat.Builder builder =
+ new NotificationCompat.Builder(context, CHANNEL_ID)
+ .setSmallIcon(com.android.settingslib.R.drawable.ic_bt_le_audio_sharing)
+ .setLocalOnly(true)
+ .setContentTitle(context.getString(R.string.share_audio_notification_title,
+ deviceName))
+ .setContentText(
+ context.getString(R.string.audio_sharing_notification_content))
+ .setOngoing(true)
+ .setSilent(true)
+ .setColor(
+ context.getColor(
+ com.android.internal.R.color
+ .system_notification_accent_color))
+ .addAction(addSourceAction)
+ .addAction(cancelAction)
+ .setTimeoutAfter(NOTIF_AUTO_DISMISS_MILLIS)
+ .addExtras(extras);
+ nm.notify(ADD_SOURCE_NOTIFICATION_ID, builder.build());
+ }
+
+ private void cancelSharingNotification(@NonNull Context context, int notifId) {
+ NotificationManager nm = context.getSystemService(NotificationManager.class);
+ if (nm != null) {
+ nm.cancel(notifId);
+ }
+ }
+
+ private void createNotificationChannelIfNeeded(@NonNull NotificationManager nm,
+ @NonNull Context context) {
+ if (nm.getNotificationChannel(CHANNEL_ID) == null) {
+ Log.d(TAG, "Create bluetooth notification channel");
+ NotificationChannel notificationChannel =
+ new NotificationChannel(
+ CHANNEL_ID,
+ context.getString(com.android.settings.R.string.bluetooth),
+ NotificationManager.IMPORTANCE_HIGH);
+ nm.createNotificationChannel(notificationChannel);
+ }
+ }
+
+ private boolean isAppInForeground(@NonNull Context context) {
+ try {
+ ActivityManager activityManager = context.getSystemService(ActivityManager.class);
+ String packageName = context.getPackageName();
+ if (context.getPackageManager().checkPermission(Manifest.permission.PACKAGE_USAGE_STATS,
+ packageName) != PackageManager.PERMISSION_GRANTED) {
+ Log.d(TAG, "check isAppInForeground, returns false due to no permission");
+ return false;
+ }
+ if (packageName != null && activityManager.getPackageImportance(packageName)
+ == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+ Log.d(TAG, "check isAppInForeground, returns true");
+ return true;
+ }
+ } catch (RuntimeException e) {
+ Log.d(TAG, "check isAppInForeground, error = " + e.getMessage());
+ }
+ return false;
}
}
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 9acdfaa..e97834f 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -48,13 +48,11 @@
import com.android.settings.core.PreferenceControllerListHelper;
import com.android.settings.flags.Flags;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settings.restriction.UserRestrictionBindingHelper;
import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.drawer.DashboardCategory;
import com.android.settingslib.drawer.Tile;
-import com.android.settingslib.preference.PreferenceScreenBindingHelper;
import com.android.settingslib.preference.PreferenceScreenCreator;
import com.android.settingslib.search.Indexable;
@@ -94,8 +92,6 @@
private boolean mListeningToCategoryChange;
private List<String> mSuppressInjectedTileKeys;
- private @Nullable UserRestrictionBindingHelper mUserRestrictionBindingHelper;
-
@Override
public void onAttach(Context context) {
super.onAttach(context);
@@ -182,13 +178,6 @@
// editing dialog is recreated (that would happen before onResume is called).
updatePreferenceStates();
}
- if (isCatalystEnabled()) {
- PreferenceScreenBindingHelper helper = getPreferenceScreenBindingHelper();
- if (helper != null) {
- mUserRestrictionBindingHelper = new UserRestrictionBindingHelper(requireContext(),
- helper);
- }
- }
}
@Override
@@ -300,15 +289,6 @@
}
@Override
- public void onDestroy() {
- if (mUserRestrictionBindingHelper != null) {
- mUserRestrictionBindingHelper.close();
- mUserRestrictionBindingHelper = null;
- }
- super.onDestroy();
- }
-
- @Override
protected abstract int getPreferenceScreenResId();
@Override
diff --git a/src/com/android/settings/development/PageAgnosticNotificationService.java b/src/com/android/settings/development/PageAgnosticNotificationService.java
index 58c26df..c89cbc0 100644
--- a/src/com/android/settings/development/PageAgnosticNotificationService.java
+++ b/src/com/android/settings/development/PageAgnosticNotificationService.java
@@ -23,6 +23,7 @@
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
+import android.os.UserHandle;
import android.provider.Settings;
import androidx.annotation.NonNull;
@@ -148,7 +149,8 @@
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Notification notification = buildNotification();
if (mNotificationManager != null) {
- mNotificationManager.notify(NOTIFICATION_ID, notification);
+ mNotificationManager.notifyAsUser(null, NOTIFICATION_ID, notification,
+ UserHandle.ALL);
}
return Service.START_REDELIVER_INTENT;
}
diff --git a/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java b/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java
index 1955f36..785d84a 100644
--- a/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceController.java
@@ -92,9 +92,10 @@
private String getSummary(long usedBytes, long totalBytes) {
NumberFormat percentageFormat = NumberFormat.getPercentInstance();
-
+ final String[] freeSpace =
+ Formatter.formatFileSize(mContext, totalBytes - usedBytes).split(" ");
return mContext.getString(R.string.storage_summary,
totalBytes == 0L ? "0" : percentageFormat.format(((double) usedBytes) / totalBytes),
- Formatter.formatFileSize(mContext, totalBytes - usedBytes));
+ freeSpace[0], freeSpace[1]);
}
}
diff --git a/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.kt b/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.kt
index f765d8c..54331aa 100644
--- a/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.kt
+++ b/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceController.kt
@@ -64,8 +64,12 @@
* Also check [getIsAvailableAndUpdateEid] for other availability check which retrieved
* asynchronously later.
*/
- override fun getAvailabilityStatus() =
- if (SubscriptionUtil.isSimHardwareVisible(mContext)) AVAILABLE else UNSUPPORTED_ON_DEVICE
+ override fun getAvailabilityStatus() = when {
+ !SubscriptionUtil.isSimHardwareVisible(mContext)
+ || Utils.isWifiOnly(mContext) -> UNSUPPORTED_ON_DEVICE
+ !mContext.userManager.isAdminUser -> DISABLED_FOR_USER
+ else -> AVAILABLE
+ }
override fun displayPreference(screen: PreferenceScreen) {
super.displayPreference(screen)
@@ -98,7 +102,6 @@
}
private fun getIsAvailableAndUpdateEid(): Boolean {
- if (!mContext.userManager.isAdminUser || Utils.isWifiOnly(mContext)) return false
eid = eidStatus?.eid ?: ""
return eid.isNotEmpty()
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java b/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java
index c62728b..ad2455e 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/AnomalyEventWrapper.java
@@ -17,6 +17,7 @@
package com.android.settings.fuelgauge.batteryusage;
import android.content.Context;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -28,7 +29,8 @@
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.core.SubSettingLauncher;
-import com.android.settings.widget.TipCardPreference;
+import com.android.settingslib.widget.BannerMessagePreference;
+import com.android.settingslib.widget.BannerMessagePreference.AttentionLevel;
import java.util.function.Function;
@@ -37,6 +39,7 @@
private final Context mContext;
private final PowerAnomalyEvent mPowerAnomalyEvent;
+ private final AttentionLevel mAttentionLevel;
private final int mCardStyleId;
private final int mResourceIndex;
@@ -51,6 +54,7 @@
// Set basic battery tips card info
mCardStyleId = mPowerAnomalyEvent.getType().getNumber();
mResourceIndex = mPowerAnomalyEvent.getKey().getNumber();
+ mAttentionLevel = mCardStyleId == 0 ? AttentionLevel.NORMAL : AttentionLevel.MEDIUM;
}
private <T> T getInfo(
@@ -104,12 +108,14 @@
return mPowerAnomalyEvent.hasEventId() ? mPowerAnomalyEvent.getEventId() : null;
}
- int getIconResId() {
- return getResourceId(R.array.battery_tips_card_icons, mCardStyleId, "drawable");
- }
-
- int getColorResId() {
- return getResourceId(R.array.battery_tips_card_colors, mCardStyleId, "color");
+ Drawable getIconDrawable() {
+ final int iconResId =
+ getResourceId(R.array.battery_tips_card_icons, mCardStyleId, "drawable");
+ Drawable drawable = mContext.getDrawable(iconResId);
+ if (drawable != null && mAttentionLevel != AttentionLevel.NORMAL) {
+ drawable.setTint(mContext.getColor(mAttentionLevel.getButtonBackgroundColorResId()));
+ }
+ return drawable;
}
String getTitleString() {
@@ -236,16 +242,16 @@
return mHighlightSlotPair;
}
- boolean updateTipsCardPreference(TipCardPreference preference) {
+ boolean updateTipsCardPreference(BannerMessagePreference preference) {
final String titleString = getTitleString();
if (TextUtils.isEmpty(titleString)) {
return false;
}
preference.setTitle(titleString);
- preference.setIconResId(getIconResId());
- preference.setTintColorResId(getColorResId());
- preference.setPrimaryButtonText(getDismissBtnString());
- preference.setSecondaryButtonText(getMainBtnString());
+ preference.setIcon(getIconDrawable());
+ preference.setAttentionLevel(mAttentionLevel);
+ preference.setNegativeButtonText(getDismissBtnString());
+ preference.setPositiveButtonText(getMainBtnString());
return true;
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
index 88f99c3..eafccdb 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryChartView.java
@@ -377,7 +377,9 @@
mTransomTop = resources.getDimensionPixelSize(R.dimen.chartview_transom_padding_top);
mTransomLineDefaultColor = Utils.getDisabled(mContext, DIVIDER_COLOR);
mTransomLineSelectedColor =
- resources.getColor(R.color.color_battery_anomaly_app_warning_selector);
+ resources.getColor(
+ com.android.settingslib.widget.preference.banner.R.color
+ .settingslib_banner_button_background_medium);
final int slotHighlightColor = Utils.getDisabled(mContext, mTransomLineSelectedColor);
mTransomIconSize = resources.getDimensionPixelSize(R.dimen.chartview_transom_icon_size);
mTransomLinePaint = new Paint();
diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
index 405b786..705ec6a 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsController.java
@@ -25,15 +25,14 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory;
-import com.android.settings.widget.TipCardPreference;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+import com.android.settingslib.widget.BannerMessagePreference;
/** Controls the update for battery tips card */
public class BatteryTipsController extends BasePreferenceController {
private static final String TAG = "BatteryTipsController";
- private static final String ROOT_PREFERENCE_KEY = "battery_tips_category";
- private static final String CARD_PREFERENCE_KEY = "battery_tips_card";
+ private static final String PREFERENCE_KEY = "battery_tips_card";
@VisibleForTesting static final String ANOMALY_KEY = "anomaly_key";
@@ -53,12 +52,12 @@
@VisibleForTesting OnAnomalyConfirmListener mOnAnomalyConfirmListener;
@VisibleForTesting OnAnomalyRejectListener mOnAnomalyRejectListener;
- @VisibleForTesting TipCardPreference mCardPreference;
+ @VisibleForTesting BannerMessagePreference mCardPreference;
@VisibleForTesting AnomalyEventWrapper mAnomalyEventWrapper = null;
@VisibleForTesting Boolean mIsAcceptable = false;
public BatteryTipsController(Context context) {
- super(context, ROOT_PREFERENCE_KEY);
+ super(context, PREFERENCE_KEY);
final FeatureFactory featureFactory = FeatureFactory.getFeatureFactory();
mMetricsFeatureProvider = featureFactory.getMetricsFeatureProvider();
}
@@ -71,7 +70,10 @@
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- mCardPreference = screen.findPreference(CARD_PREFERENCE_KEY);
+ mCardPreference = screen.findPreference(PREFERENCE_KEY);
+
+ // Set preference as invisible since there is no default tips.
+ mCardPreference.setVisible(false);
}
void setOnAnomalyConfirmListener(OnAnomalyConfirmListener listener) {
@@ -117,20 +119,13 @@
return;
}
- mCardPreference.setPrimaryButtonAction(
- () -> {
- onBatteryTipsCardDismiss(anomalyKeyNumber);
- return null;
- });
- mCardPreference.setSecondaryButtonAction(
- () -> {
- onBatteryTipsCardAccept(anomalyKeyNumber);
- return null;
- });
+ mCardPreference.setNegativeButtonOnClickListener(
+ view -> onBatteryTipsCardDismiss(anomalyKeyNumber));
+ mCardPreference.setPositiveButtonOnClickListener(
+ view -> onBatteryTipsCardAccept(anomalyKeyNumber));
- mCardPreference.setPrimaryButtonVisibility(true);
- mCardPreference.setSecondaryButtonVisibility(true);
- mCardPreference.buildContent();
+ mCardPreference.setPositiveButtonVisible(true);
+ mCardPreference.setNegativeButtonVisible(true);
mCardPreference.setVisible(true);
mMetricsFeatureProvider.action(
/* attribution= */ SettingsEnums.FUELGAUGE_BATTERY_HISTORY_DETAIL,
diff --git a/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java b/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
index 22e3431..121bd82 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/LowStorageSlice.java
@@ -64,7 +64,9 @@
// Generate Low storage Slice.
final String percentageString = NumberFormat.getPercentInstance().format(usedPercentage);
- final String freeSizeString = Formatter.formatFileSize(mContext, info.freeBytes);
+ final String[] freeSizeString =
+ Formatter.formatFileSize(mContext, info.freeBytes).split(" ");
+
final ListBuilder listBuilder = new ListBuilder(mContext,
CustomSliceRegistry.LOW_STORAGE_SLICE_URI, ListBuilder.INFINITY).setAccentColor(
Utils.getColorAccentDefaultColor(mContext));
@@ -74,7 +76,7 @@
// For clients that ignore error checking, a generic storage slice will be given.
final CharSequence titleStorage = mContext.getText(R.string.storage_settings);
final String summaryStorage = mContext.getString(R.string.storage_summary,
- percentageString, freeSizeString);
+ percentageString, freeSizeString[0], freeSizeString[1]);
return listBuilder
.addRow(buildRowBuilder(titleStorage, summaryStorage, icon))
diff --git a/src/com/android/settings/notification/modes/ConfigurationActivityHelper.java b/src/com/android/settings/notification/modes/ConfigurationActivityHelper.java
index d001651..ad76802 100644
--- a/src/com/android/settings/notification/modes/ConfigurationActivityHelper.java
+++ b/src/com/android/settings/notification/modes/ConfigurationActivityHelper.java
@@ -48,21 +48,22 @@
Intent getConfigurationActivityIntentForMode(ZenMode zenMode,
Function<ComponentName, ComponentInfo> approvedServiceFinder) {
- String owner = zenMode.getRule().getPackageName();
+ ZenMode.Owner owner = zenMode.getOwner();
ComponentName configActivity = null;
- if (zenMode.getRule().getConfigurationActivity() != null) {
+ if (owner.configurationActivity() != null) {
// If a configuration activity is present, use that directly in the intent
- configActivity = zenMode.getRule().getConfigurationActivity();
+ configActivity = owner.configurationActivity();
} else {
// Otherwise, look for a condition provider service for the rule's package
- ComponentInfo ci = approvedServiceFinder.apply(zenMode.getRule().getOwner());
+ ComponentInfo ci = approvedServiceFinder.apply(owner.conditionProvider());
if (ci != null) {
configActivity = extractConfigurationActivityFromComponent(ci);
}
}
if (configActivity != null
- && (owner == null || isSameOwnerPackage(owner, configActivity))
+ && (owner.packageName() == null
+ || isSameOwnerPackage(owner.packageName(), configActivity))
&& isResolvableActivity(configActivity)) {
return new Intent()
.setComponent(configActivity)
diff --git a/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java
index 72ff524..dbbc486 100644
--- a/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeButtonPreferenceController.java
@@ -51,7 +51,7 @@
@Override
public boolean isAvailable(ZenMode zenMode) {
return zenMode.isEnabled()
- && (zenMode.isActive() || zenMode.getRule().isManualInvocationAllowed());
+ && (zenMode.isActive() || zenMode.isManualInvocationAllowed());
}
@Override
diff --git a/src/com/android/settings/notification/modes/ZenModeEditNameIconFragment.java b/src/com/android/settings/notification/modes/ZenModeEditNameIconFragment.java
index 60f7316..f043298 100644
--- a/src/com/android/settings/notification/modes/ZenModeEditNameIconFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModeEditNameIconFragment.java
@@ -54,8 +54,8 @@
return;
}
- modeToUpdate.getRule().setName(mode.getRule().getName());
- modeToUpdate.getRule().setIconResId(mode.getRule().getIconResId());
+ modeToUpdate.setName(mode.getName());
+ modeToUpdate.setIconResId(mode.getIconResId());
requireBackend().updateMode(modeToUpdate);
finish();
}
diff --git a/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentBase.java b/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentBase.java
index 6dd9076..20a30f7 100644
--- a/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentBase.java
+++ b/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentBase.java
@@ -128,13 +128,13 @@
@VisibleForTesting
final void setModeName(String name) {
- checkNotNull(mZenMode).getRule().setName(Strings.nullToEmpty(name));
+ checkNotNull(mZenMode).setName(Strings.nullToEmpty(name));
forceUpdatePreferences(); // Updates confirmation button.
}
@VisibleForTesting
final void setModeIcon(@DrawableRes int iconResId) {
- checkNotNull(mZenMode).getRule().setIconResId(iconResId);
+ checkNotNull(mZenMode).setIconResId(iconResId);
forceUpdatePreferences(); // Updates icon at the top.
}
diff --git a/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java
index 18e3fc1..7bf2e88 100644
--- a/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceController.java
@@ -16,6 +16,8 @@
package com.android.settings.notification.modes;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import android.content.Context;
import android.service.notification.ZenModeConfig;
@@ -24,6 +26,7 @@
import androidx.preference.TwoStatePreference;
import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
import com.android.settingslib.notification.modes.ZenModesBackend;
/**
@@ -40,7 +43,7 @@
@Override
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
- mSchedule = ZenModeConfig.tryParseScheduleConditionId(zenMode.getRule().getConditionId());
+ mSchedule = checkNotNull(ZenModeSchedules.getTimeSchedule(zenMode));
((TwoStatePreference) preference).setChecked(mSchedule.exitAtAlarm);
}
diff --git a/src/com/android/settings/notification/modes/ZenModeNewCustomFragment.java b/src/com/android/settings/notification/modes/ZenModeNewCustomFragment.java
index d7dbaaf..8ff23e7 100644
--- a/src/com/android/settings/notification/modes/ZenModeNewCustomFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModeNewCustomFragment.java
@@ -47,8 +47,7 @@
? requireContext().getString(R.string.zen_mode_new_custom_default_name)
: mode.getName();
- ZenMode created = requireBackend().addCustomManualMode(modeName,
- mode.getRule().getIconResId());
+ ZenMode created = requireBackend().addCustomManualMode(modeName, mode.getIconResId());
if (created != null) {
// Open the mode view fragment and close the "add mode" fragment, so exiting the mode
// view goes back to previous screen (which should be the modes list).
diff --git a/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java
index 4f45c5c8..6788236 100644
--- a/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceController.java
@@ -32,6 +32,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.R;
import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
import com.android.settingslib.notification.modes.ZenModesBackend;
import java.util.ArrayList;
@@ -85,7 +86,7 @@
mReply.setOnPreferenceChangeListener(mReplyChangeListener);
// Parse the zen mode's condition to update our EventInfo object.
- mEvent = ZenModeConfig.tryParseEventConditionId(zenMode.getRule().getConditionId());
+ mEvent = ZenModeSchedules.getCalendarSchedule(zenMode);
if (mEvent != null) {
reloadCalendar();
updatePrefValues();
diff --git a/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java b/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java
index 651b7cc..d5e6a75 100644
--- a/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceController.java
@@ -32,6 +32,7 @@
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
import com.android.settingslib.notification.modes.ZenModesBackend;
import com.android.settingslib.widget.LayoutPreference;
@@ -62,7 +63,7 @@
@Override
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
- mSchedule = ZenModeConfig.tryParseScheduleConditionId(zenMode.getRule().getConditionId());
+ mSchedule = ZenModeSchedules.getTimeSchedule(zenMode);
LayoutPreference layoutPref = (LayoutPreference) preference;
TextView start = layoutPref.findViewById(R.id.start_time);
diff --git a/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java b/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
index bbed5b9..a0e5b50 100644
--- a/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceController.java
@@ -20,7 +20,6 @@
import static android.app.AutomaticZenRule.TYPE_DRIVING;
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_CALENDAR;
import static android.app.AutomaticZenRule.TYPE_SCHEDULE_TIME;
-import static android.service.notification.ZenModeConfig.tryParseScheduleConditionId;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
@@ -43,6 +42,7 @@
import com.android.settings.Utils;
import com.android.settingslib.PrimarySwitchPreference;
import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
import com.android.settingslib.notification.modes.ZenModesBackend;
import com.google.common.base.Strings;
@@ -105,8 +105,7 @@
// [Clock Icon] 9:00 - 17:00 / Sun-Mon
preference.setIcon(com.android.internal.R.drawable.ic_zen_mode_type_schedule_time);
- ZenModeConfig.ScheduleInfo schedule =
- tryParseScheduleConditionId(mode.getRule().getConditionId());
+ ZenModeConfig.ScheduleInfo schedule = ZenModeSchedules.getTimeSchedule(mode);
if (schedule != null) {
preference.setTitle(SystemZenRules.getTimeSummary(mContext, schedule));
String shortDaysSummary = SystemZenRules.getDaysOfWeekShort(mContext, schedule);
@@ -138,7 +137,7 @@
@SuppressLint("SwitchIntDef")
private void setUpForAppTrigger(Preference preference, ZenMode mode) {
// App-owned mode may have triggerDescription, configurationActivity, or both/neither.
- mServiceListing.loadApprovedComponents(mode.getRule().getPackageName());
+ mServiceListing.loadApprovedComponents(mode.getOwnerPackage());
Intent configurationIntent =
mConfigurationActivityHelper.getConfigurationActivityIntentForMode(
mode, mServiceListing::findService);
@@ -152,11 +151,11 @@
String summary;
if (!Strings.isNullOrEmpty(mode.getTriggerDescription())) {
summary = mode.getTriggerDescription();
- } else if (!Strings.isNullOrEmpty(mode.getRule().getPackageName())) {
+ } else if (!Strings.isNullOrEmpty(mode.getOwnerPackage())) {
String appName = null;
try {
ApplicationInfo appInfo = mPackageManager.getApplicationInfo(
- mode.getRule().getPackageName(), 0);
+ mode.getOwnerPackage(), 0);
appName = appInfo.loadLabel(mPackageManager).toString();
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Couldn't resolve owner for mode: " + mode);
@@ -219,7 +218,7 @@
private void setModeEnabled(boolean enabled) {
saveMode((zenMode) -> {
if (enabled != zenMode.isEnabled()) {
- zenMode.getRule().setEnabled(enabled);
+ zenMode.setEnabled(enabled);
}
return zenMode;
});
diff --git a/src/com/android/settings/notification/modes/ZenModesListFragment.java b/src/com/android/settings/notification/modes/ZenModesListFragment.java
index 00f652d..76a4366 100644
--- a/src/com/android/settings/notification/modes/ZenModesListFragment.java
+++ b/src/com/android/settings/notification/modes/ZenModesListFragment.java
@@ -125,7 +125,7 @@
// If we find a new mode owned by the same package, presumably that's it. Open its page.
Optional<ZenMode> createdZenMode = mBackend.getModes().stream()
.filter(m -> !previousIds.contains(m.getId()))
- .filter(m -> m.getRule().getPackageName().equals(activityInvoked.getPackageName()))
+ .filter(m -> activityInvoked.getPackageName().equals(m.getOwnerPackage()))
.findFirst();
createdZenMode.ifPresent(
mode ->
diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java
index 28d2f4f..aacc11d 100644
--- a/src/com/android/settings/users/UserSettings.java
+++ b/src/com/android/settings/users/UserSettings.java
@@ -18,6 +18,9 @@
import static com.android.settingslib.Utils.getColorAttrDefaultColor;
+import android.Manifest;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Dialog;
@@ -83,6 +86,7 @@
import com.android.settingslib.drawable.CircleFramedDrawable;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.search.SearchIndexableRaw;
+import com.android.settingslib.users.CreateUserActivity;
import com.android.settingslib.users.CreateUserDialogController;
import com.android.settingslib.users.EditUserInfoController;
import com.android.settingslib.users.GrantAdminDialogController;
@@ -91,6 +95,7 @@
import com.google.android.setupcompat.util.WizardManagerHelper;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
@@ -171,6 +176,7 @@
private static final int REQUEST_CHOOSE_LOCK = 10;
private static final int REQUEST_EDIT_GUEST = 11;
+ private static final int REQUEST_ADD_USER = 12;
static final int RESULT_GUEST_REMOVED = 100;
@@ -234,6 +240,8 @@
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private CharSequence mPendingUserName;
+ @Nullable
+ private String mPendingUserIconPath;
private Drawable mPendingUserIcon;
private boolean mPendingUserIsAdmin;
@@ -570,6 +578,14 @@
if (resultCode != Activity.RESULT_CANCELED && hasLockscreenSecurity()) {
addUserNow(USER_TYPE_RESTRICTED_PROFILE);
}
+ } else if (Flags.placeAddUserDialogWithinActivity() && requestCode == REQUEST_ADD_USER) {
+ if (resultCode == Activity.RESULT_OK) {
+ mPendingUserName = data.getStringExtra(CreateUserActivity.EXTRA_USER_NAME);
+ mPendingUserIsAdmin = data.getBooleanExtra(CreateUserActivity.EXTRA_IS_ADMIN,
+ false);
+ mPendingUserIconPath = data.getStringExtra(CreateUserActivity.EXTRA_USER_ICON_PATH);
+ addUserNow(USER_TYPE_USER);
+ }
} else if (mGuestUserAutoCreated && requestCode == REQUEST_EDIT_GUEST
&& resultCode == RESULT_GUEST_REMOVED) {
scheduleGuestCreation();
@@ -921,7 +937,7 @@
getActivity(),
this::startActivityForResult,
canCreateAdminUser(),
- (userName, userIcon, isAdmin) -> {
+ (userName, userIcon, iconPath, isAdmin) -> {
mPendingUserIcon = userIcon;
mPendingUserName = userName;
mPendingUserIsAdmin = isAdmin;
@@ -1040,6 +1056,8 @@
createUser(userType, mAddingUserName);
}
+ @RequiresPermission(allOf = {Manifest.permission.MANAGE_USERS,
+ Manifest.permission.INTERACT_ACROSS_USERS_FULL})
@VisibleForTesting
void createUser(final int userType, String userName) {
Context context = getContext();
@@ -1065,18 +1083,25 @@
mAddingUser = false;
mPendingUserIcon = null;
mPendingUserName = null;
+ mPendingUserIconPath = null;
onUserCreationFailed();
return;
}
Future<?> unusedSettingIconFuture = ThreadUtils.postOnBackgroundThread(() -> {
- Drawable newUserIcon = selectedUserIcon;
- if (newUserIcon == null) {
- newUserIcon = UserIcons.getDefaultUserIcon(resources, user.id, false);
+ if (Flags.placeAddUserDialogWithinActivity() && mPendingUserIconPath != null) {
+ Bitmap bitmap = BitmapFactory.decodeFile(mPendingUserIconPath);
+ mUserManager.setUserIcon(user.id, bitmap);
+ new File(mPendingUserIconPath).delete();
+ mPendingUserIconPath = null;
+ } else {
+ Drawable newUserIcon = selectedUserIcon;
+ if (newUserIcon == null) {
+ newUserIcon = UserIcons.getDefaultUserIcon(resources, user.id, false);
+ }
+ mUserManager.setUserIcon(user.id, UserIcons.convertToBitmapAtUserIconSize(
+ resources, newUserIcon));
}
- mUserManager.setUserIcon(
- user.id, UserIcons.convertToBitmapAtUserIconSize(
- resources, newUserIcon));
});
mPendingUserIcon = null;
@@ -1687,7 +1712,13 @@
if (mUserCaps.mCanAddRestrictedProfile) {
showDialog(DIALOG_CHOOSE_USER_TYPE);
} else {
- onAddUserClicked(USER_TYPE_USER);
+ if (Flags.placeAddUserDialogWithinActivity()) {
+ startActivityForResult(CreateUserActivity.createIntentForStart(getActivity(),
+ canCreateAdminUser(), Utils.FILE_PROVIDER_AUTHORITY),
+ REQUEST_ADD_USER);
+ } else {
+ onAddUserClicked(USER_TYPE_USER);
+ }
}
return true;
} else if (pref == mAddSupervisedUser) {
diff --git a/src/com/android/settings/wifi/AddNetworkFragment.java b/src/com/android/settings/wifi/AddNetworkFragment.java
index f5bf5ee..38bc0b5 100644
--- a/src/com/android/settings/wifi/AddNetworkFragment.java
+++ b/src/com/android/settings/wifi/AddNetworkFragment.java
@@ -234,6 +234,9 @@
activity.getSystemService(WifiManager.class).save(config, saveListener);
} else {
+ if (!mUIController.canFinish()) {
+ return;
+ }
Intent intent = new Intent();
intent.putExtra(WIFI_CONFIG_KEY, config);
activity.setResult(Activity.RESULT_OK, intent);
diff --git a/src/com/android/settings/wifi/WifiConfigController2.java b/src/com/android/settings/wifi/WifiConfigController2.java
index 1ea0103..1bf1102 100644
--- a/src/com/android/settings/wifi/WifiConfigController2.java
+++ b/src/com/android/settings/wifi/WifiConfigController2.java
@@ -77,6 +77,7 @@
import com.android.settings.wifi.details2.WifiPrivacyPreferenceController;
import com.android.settings.wifi.details2.WifiPrivacyPreferenceController2;
import com.android.settings.wifi.dpp.WifiDppUtils;
+import com.android.settings.wifi.utils.SsidInputGroup;
import com.android.settingslib.Utils;
import com.android.settingslib.utils.ThreadUtils;
import com.android.wifi.flags.Flags;
@@ -228,7 +229,7 @@
private final boolean mHideMeteredAndPrivacy;
private final WifiManager mWifiManager;
private final AndroidKeystoreAliasLoader mAndroidKeystoreAliasLoader;
- private TextView mSsidView;
+ private SsidInputGroup mSsidInputGroup;
private final Context mContext;
@@ -298,6 +299,7 @@
wepWarningLayout.setVisibility(View.VISIBLE);
}
+ mSsidInputGroup = new SsidInputGroup(mContext, mView, R.id.ssid_layout, R.id.ssid);
mSsidScanButton = (ImageButton) mView.findViewById(R.id.ssid_scanner_button);
mIpSettingsSpinner = (Spinner) mView.findViewById(R.id.ip_settings);
mIpSettingsSpinner.setOnItemSelectedListener(this);
@@ -544,13 +546,13 @@
&& !isValidSaePassword(mPasswordView.getText().toString())))) {
passwordInvalid = true;
}
- if ((mSsidView != null && mSsidView.length() == 0)
- // If WifiEntry is not saved, apply passwordInvalid check
- || ((mWifiEntry == null || !mWifiEntry.isSaved()) && passwordInvalid
- // If WifiEntry is saved (modifying network) and password is changed, apply
- // Invalid password check
- || mWifiEntry != null && mWifiEntry.isSaved() && passwordInvalid
- && mPasswordView.length() > 0)) {
+ if ((mWifiEntry == null || !mWifiEntry.isSaved()) && passwordInvalid) {
+ // If WifiEntry is not saved, apply passwordInvalid check
+ enabled = false;
+ } else if (mWifiEntry != null && mWifiEntry.isSaved() && passwordInvalid
+ && mPasswordView.length() > 0) {
+ // If WifiEntry is saved (modifying network) and password is changed, apply
+ // Invalid password check
enabled = false;
} else {
enabled = ipAndProxyFieldsAreValid();
@@ -586,16 +588,21 @@
return enabled;
}
+ boolean canFinish() {
+ if (!mSsidInputGroup.validate()) {
+ Log.w(TAG, "Can't finish because SSID is invalid!");
+ return false;
+ }
+ return true;
+ }
+
void showWarningMessagesIfAppropriate() {
mView.findViewById(R.id.no_user_cert_warning).setVisibility(View.GONE);
mView.findViewById(R.id.no_domain_warning).setVisibility(View.GONE);
mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.GONE);
- if (mSsidView != null) {
- final String ssid = mSsidView.getText().toString();
- if (WifiUtils.isSSIDTooLong(ssid)) {
- mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.VISIBLE);
- }
+ if (WifiUtils.isSSIDTooLong(mSsidInputGroup.getText())) {
+ mView.findViewById(R.id.ssid_too_long_warning).setVisibility(View.VISIBLE);
}
if (mEapCaCertSpinner != null
&& mView.findViewById(R.id.l_ca_cert).getVisibility() != View.GONE) {
@@ -628,7 +635,7 @@
WifiConfiguration config;
if (mWifiEntry == null) {
config = new WifiConfiguration();
- config.SSID = "\"" + mSsidView.getText().toString() + "\"";
+ config.SSID = "\"" + mSsidInputGroup.getText() + "\"";
// If the user adds a network manually, assume that it is hidden.
config.hiddenSSID = mHiddenSettingsSpinner.getSelectedItemPosition() == HIDDEN_NETWORK;
} else if (mWifiEntry.isSaved()) {
@@ -1823,8 +1830,7 @@
private void configureSecuritySpinner() {
mConfigUi.setTitle(R.string.wifi_add_network);
- mSsidView = (TextView) mView.findViewById(R.id.ssid);
- mSsidView.addTextChangedListener(this);
+ mSsidInputGroup.addTextChangedListener(this);
mSecuritySpinner = ((Spinner) mView.findViewById(R.id.security));
mSecuritySpinner.setOnItemSelectedListener(this);
diff --git a/src/com/android/settings/wifi/calling/OWNERS b/src/com/android/settings/wifi/calling/OWNERS
index 87e5fcc..fc903a3 100644
--- a/src/com/android/settings/wifi/calling/OWNERS
+++ b/src/com/android/settings/wifi/calling/OWNERS
@@ -1,7 +1,6 @@
# Default reviewers for this and subdirectories.
allenwtsu@google.com
andychou@google.com
-bonianchen@google.com
leechou@google.com
songferngwang@google.com
tomhsu@google.com
diff --git a/src/com/android/settings/wifi/utils/SsidInputGroup.kt b/src/com/android/settings/wifi/utils/SsidInputGroup.kt
new file mode 100644
index 0000000..5d8f8d4
--- /dev/null
+++ b/src/com/android/settings/wifi/utils/SsidInputGroup.kt
@@ -0,0 +1,34 @@
+/*
+ * 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.wifi.utils
+
+import android.content.Context
+import android.view.View
+import com.android.settings.R
+
+/** TextInputGroup for Wi-Fi SSID. */
+class SsidInputGroup(private val context: Context, view: View, layoutId: Int, editTextId: Int) :
+ TextInputGroup(view, layoutId, editTextId) {
+
+ fun validate(): Boolean {
+ if (getText().isEmpty()) {
+ setError(context.getString(R.string.wifi_ssid_hint))
+ return false
+ }
+ return true
+ }
+}
diff --git a/src/com/android/settings/wifi/utils/TextInputGroup.kt b/src/com/android/settings/wifi/utils/TextInputGroup.kt
new file mode 100644
index 0000000..8006dad
--- /dev/null
+++ b/src/com/android/settings/wifi/utils/TextInputGroup.kt
@@ -0,0 +1,68 @@
+/*
+ * 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.wifi.utils
+
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.View
+import android.widget.EditText
+import com.google.android.material.textfield.TextInputLayout
+
+/** A widget that wraps the relationship work between a TextInputLayout and an EditText. */
+open class TextInputGroup(
+ private val view: View,
+ private val layoutId: Int,
+ private val editTextId: Int,
+) {
+
+ private val View.layout: TextInputLayout?
+ get() = findViewById(layoutId)
+
+ private val View.editText: EditText?
+ get() = findViewById(editTextId)
+
+ private val textWatcher =
+ object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
+
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
+
+ override fun afterTextChanged(s: Editable?) {
+ view.layout?.isErrorEnabled = false
+ }
+ }
+
+ init {
+ addTextChangedListener(textWatcher)
+ }
+
+ fun addTextChangedListener(watcher: TextWatcher) {
+ view.editText?.addTextChangedListener(watcher)
+ }
+
+ fun getText(): String {
+ return view.editText?.text?.toString() ?: ""
+ }
+
+ fun setText(text: String) {
+ view.editText?.setText(text)
+ }
+
+ fun setError(errorMessage: String?) {
+ view.layout?.apply { error = errorMessage }
+ }
+}
diff --git a/tests/componenttests/src/com/android/settings/biometrics/BiometricEnrollActivityTest.java b/tests/componenttests/src/com/android/settings/biometrics/BiometricEnrollActivityTest.java
index 0cb73c1..eb28dfb 100644
--- a/tests/componenttests/src/com/android/settings/biometrics/BiometricEnrollActivityTest.java
+++ b/tests/componenttests/src/com/android/settings/biometrics/BiometricEnrollActivityTest.java
@@ -51,8 +51,8 @@
import com.android.internal.widget.LockPatternChecker;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockscreenCredential;
-import com.android.settings.biometrics.face.FaceEnrollIntroduction;
-import com.android.settings.biometrics.fingerprint.FingerprintEnrollIntroduction;
+import com.android.settings.biometrics.face.FaceEnroll;
+import com.android.settings.biometrics.fingerprint.FingerprintEnroll;
import com.android.settings.password.ChooseLockGeneric;
import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.password.ConfirmLockPassword;
@@ -157,8 +157,8 @@
try (ActivityScenario<BiometricEnrollActivity> scenario =
ActivityScenario.launch(intent)) {
intended(hasComponent(mHasFace && !mHasFingerprint
- ? FaceEnrollIntroduction.class.getName()
- : FingerprintEnrollIntroduction.class.getName()));
+ ? FaceEnroll.class.getName()
+ : FingerprintEnroll.class.getName()));
}
}
diff --git a/tests/robotests/src/com/android/settings/accessibility/MagnificationModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/MagnificationModePreferenceControllerTest.java
index 0bc3862..d0d0d37 100644
--- a/tests/robotests/src/com/android/settings/accessibility/MagnificationModePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/MagnificationModePreferenceControllerTest.java
@@ -17,8 +17,6 @@
package com.android.settings.accessibility;
import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
-import static com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
-import static com.android.settings.accessibility.MagnificationModePreferenceController.MagnificationModeInfo;
import static com.google.common.truth.Truth.assertThat;
@@ -37,6 +35,7 @@
import android.widget.ListView;
import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.preference.Preference;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
@@ -44,6 +43,9 @@
import com.android.settings.DialogCreatable;
import com.android.settings.R;
+import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
+import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
+import com.android.settings.accessibility.MagnificationModePreferenceController.MagnificationModeInfo;
import com.android.settings.utils.AnnotationSpan;
import org.junit.Before;
@@ -82,6 +84,8 @@
mScreen.addPreference(mModePreference);
MagnificationCapabilities.setCapabilities(mContext, MAGNIFICATION_MODE_DEFAULT);
mController = new MagnificationModePreferenceController(mContext, PREF_KEY);
+ mController.setDialogHelper(mDialogHelper);
+ mDialogHelper.setDialogDelegate(mController);
showPreferenceOnTheScreen(null);
}
@@ -107,7 +111,7 @@
performItemClickWith(MagnificationMode.WINDOW);
reshowPreferenceOnTheScreen();
- mDialogHelper.showDialog(MagnificationModePreferenceController.DIALOG_MAGNIFICATION_MODE);
+ mDialogHelper.showDialog(DialogEnums.DIALOG_MAGNIFICATION_MODE);
assertThat(getCheckedModeFromDialog()).isEqualTo(
MagnificationMode.WINDOW);
@@ -123,7 +127,7 @@
DialogInterface.BUTTON_POSITIVE);
verify(mDialogHelper, never()).showDialog(
- MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
+ DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
}
@Test
@@ -135,8 +139,7 @@
mController.onMagnificationModeDialogPositiveButtonClicked(mDialogHelper.getDialog(),
DialogInterface.BUTTON_POSITIVE);
- verify(mDialogHelper).showDialog(
- MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
+ verify(mDialogHelper).showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
}
@Test
@@ -148,20 +151,17 @@
mController.onMagnificationModeDialogPositiveButtonClicked(mDialogHelper.getDialog(),
DialogInterface.BUTTON_POSITIVE);
- verify(mDialogHelper).showDialog(
- MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
+ verify(mDialogHelper).showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
}
@Test
public void onTripleTapWarningDialogNegativeButtonClicked_showModeDialog() {
- mDialogHelper.showDialog(
- MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
+ mDialogHelper.showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
mController.onMagnificationTripleTapWarningDialogNegativeButtonClicked(
mDialogHelper.getDialog(), DialogInterface.BUTTON_NEGATIVE);
- verify(mDialogHelper).showDialog(
- MagnificationModePreferenceController.DIALOG_MAGNIFICATION_MODE);
+ verify(mDialogHelper).showDialog(DialogEnums.DIALOG_MAGNIFICATION_MODE);
}
@Test
@@ -182,8 +182,7 @@
@Test
public void checkSpansInTripleTapWarningDialog_existAnnotationSpan() {
- mDialogHelper.showDialog(
- MagnificationModePreferenceController.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
+ mDialogHelper.showDialog(DialogEnums.DIALOG_MAGNIFICATION_TRIPLE_TAP_WARNING);
final View contentView = mDialogHelper.getDialog().findViewById(android.R.id.content);
final TextView messageView = contentView.findViewById(R.id.message);
final CharSequence textInTripleTapWarningDialog = messageView.getText();
@@ -256,13 +255,11 @@
}
private void showPreferenceOnTheScreen(Bundle savedInstanceState) {
- mController.setDialogHelper(mDialogHelper);
mController.onCreate(savedInstanceState);
mController.displayPreference(mScreen);
}
- private static class TestDialogHelper implements DialogCreatable,
- MagnificationModePreferenceController.DialogHelper {
+ private static class TestDialogHelper implements DialogCreatable, DialogHelper {
private DialogCreatable mDialogDelegate;
private Dialog mDialog;
@@ -271,11 +268,11 @@
mDialog = onCreateDialog(dialogId);
}
- @Override
- public void setDialogDelegate(DialogCreatable delegate) {
+ public void setDialogDelegate(@NonNull DialogCreatable delegate) {
mDialogDelegate = delegate;
}
+ @NonNull
@Override
public Dialog onCreateDialog(int dialogId) {
return mDialogDelegate.onCreateDialog(dialogId);
diff --git a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
index ae059dd..4b28085 100644
--- a/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragmentTest.java
@@ -64,6 +64,8 @@
import com.android.settings.DialogCreatable;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.accessibility.AccessibilityDialogUtils.DialogEnums;
+import com.android.settings.accessibility.MagnificationCapabilities.MagnificationMode;
import com.android.settings.testutils.shadow.ShadowAccessibilityManager;
import com.android.settings.testutils.shadow.ShadowDeviceConfig;
import com.android.settings.testutils.shadow.ShadowStorageManager;
@@ -550,7 +552,8 @@
ToggleScreenMagnificationPreferenceFragment fragment = mFragController.create(
R.id.main_content, /* bundle= */ null).start().resume().get();
- DialogCreatable dialogDelegate = ReflectionHelpers.getField(fragment, "mDialogDelegate");
+ DialogCreatable dialogDelegate = ReflectionHelpers.getField(fragment,
+ "mMagnificationModeDialogDelegate");
List<LifecycleObserver> lifecycleObservers = ReflectionHelpers.getField(
fragment.getSettingsLifecycle(), "mObservers");
assertThat(dialogDelegate).isInstanceOf(MagnificationModePreferenceController.class);
@@ -592,19 +595,19 @@
}
@Test
- public void onCreateDialog_setDialogDelegate_invokeDialogDelegate() {
+ public void onCreateDialog_setMagnificationModeDialogDelegate_invokeDialogDelegate() {
ToggleScreenMagnificationPreferenceFragment fragment =
mFragController.create(
R.id.main_content, /* bundle= */ null).start().resume().get();
final DialogCreatable dialogDelegate = mock(DialogCreatable.class, RETURNS_DEEP_STUBS);
- when(dialogDelegate.getDialogMetricsCategory(anyInt())).thenReturn(1);
- fragment.setDialogDelegate(dialogDelegate);
+ final int dialogId = DialogEnums.DIALOG_MAGNIFICATION_MODE;
+ when(dialogDelegate.getDialogMetricsCategory(anyInt())).thenReturn(dialogId);
+ fragment.setMagnificationModeDialogDelegate(dialogDelegate);
- fragment.onCreateDialog(1);
- fragment.getDialogMetricsCategory(1);
-
- verify(dialogDelegate).onCreateDialog(1);
- verify(dialogDelegate).getDialogMetricsCategory(1);
+ fragment.onCreateDialog(dialogId);
+ fragment.getDialogMetricsCategory(dialogId);
+ verify(dialogDelegate).onCreateDialog(dialogId);
+ verify(dialogDelegate).getDialogMetricsCategory(dialogId);
}
@Test
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
index 38a607a..78c771c 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePairingDetailBaseTest.java
@@ -18,7 +18,6 @@
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BT_DEVICE_TO_AUTO_ADD_SOURCE;
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_PAIR_AND_JOIN_SHARING;
-import static com.android.settingslib.bluetooth.devicesettings.data.repository.DeviceSettingServiceConnection.METADATA_FAST_PAIR_CUSTOMIZED_FIELDS;
import static com.google.common.truth.Truth.assertThat;
@@ -37,7 +36,6 @@
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothStatusCodes;
import android.content.Context;
@@ -66,15 +64,9 @@
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowFragment;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
-import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
-import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
-import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.flags.Flags;
-import com.google.common.collect.ImmutableList;
-
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -122,14 +114,6 @@
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private LocalBluetoothManager mLocalManager;
@Mock
- private CachedBluetoothDeviceManager mDeviceManager;
- @Mock
- private LocalBluetoothProfileManager mProfileManager;
- @Mock
- private LocalBluetoothLeBroadcast mBroadcast;
- @Mock
- private LocalBluetoothLeBroadcastAssistant mAssistant;
- @Mock
private CachedBluetoothDevice mCachedBluetoothDevice;
@Mock
private Drawable mDrawable;
@@ -221,7 +205,6 @@
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
mFragment.mSelectedList.add(mBluetoothDevice);
setUpFragmentWithShareThenPairIntent(false);
- setUpAudioSharingStates(/* enabled = */ false, /* needSetTempBondMetadata = */ false);
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
verify(mFragment).finish();
@@ -236,31 +219,6 @@
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
mFragment.mSelectedList.add(mBluetoothDevice);
setUpFragmentWithShareThenPairIntent(true);
- setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ false);
- mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
- shadowOf(Looper.getMainLooper()).idle();
-
- ProgressDialogFragment progressDialog = mFragment.mProgressDialog;
- assertThat(progressDialog).isNotNull();
- assertThat(progressDialog.getMessage()).isEqualTo(
- mContext.getString(R.string.progress_dialog_connect_device_content,
- TEST_DEVICE_ADDRESS));
- assertThat(
- ShadowDialogFragment.isIsShowing(ProgressDialogFragment.class.getName())).isTrue();
- verify(mFragment, never()).finish();
-
- ShadowDialogFragment.reset();
- }
-
- @Test
- @Config(shadows = ShadowDialogFragment.class)
- @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
- public void onDeviceBondStateChanged_bonded_pairAfterShare_handle() {
- ShadowDialogFragment.reset();
- when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
- mFragment.mSelectedList.add(mBluetoothDevice);
- setUpFragmentWithShareThenPairIntent(false);
- setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ true);
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
shadowOf(Looper.getMainLooper()).idle();
@@ -283,7 +241,6 @@
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
mFragment.mSelectedList.add(mBluetoothDevice);
setUpFragmentWithShareThenPairIntent(false);
- setUpAudioSharingStates(/* enabled = */ false, /* needSetTempBondMetadata = */ false);
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
verify(mBluetoothAdapter, never()).addOnMetadataChangedListener(any(BluetoothDevice.class),
@@ -297,21 +254,6 @@
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
mFragment.mSelectedList.add(mBluetoothDevice);
setUpFragmentWithShareThenPairIntent(true);
- setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ false);
- mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
-
- verify(mBluetoothAdapter).addOnMetadataChangedListener(eq(mBluetoothDevice),
- any(Executor.class),
- any(BluetoothAdapter.OnMetadataChangedListener.class));
- }
-
- @Test
- @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
- public void onDeviceBondStateChanged_bonding_pairAfterShare_addListener() {
- when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
- mFragment.mSelectedList.add(mBluetoothDevice);
- setUpFragmentWithShareThenPairIntent(false);
- setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ true);
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
verify(mBluetoothAdapter).addOnMetadataChangedListener(eq(mBluetoothDevice),
@@ -337,21 +279,6 @@
when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
mFragment.mSelectedList.add(mBluetoothDevice);
setUpFragmentWithShareThenPairIntent(true);
- setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ false);
- mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
- mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_NONE);
-
- verify(mBluetoothAdapter).removeOnMetadataChangedListener(eq(mBluetoothDevice),
- any(BluetoothAdapter.OnMetadataChangedListener.class));
- }
-
- @Test
- @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
- public void onDeviceBondStateChanged_unbonded_pairAfterShare_removeListener() {
- when(mCachedBluetoothDevice.getDevice()).thenReturn(mBluetoothDevice);
- mFragment.mSelectedList.add(mBluetoothDevice);
- setUpFragmentWithShareThenPairIntent(false);
- setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ true);
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDING);
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_NONE);
@@ -387,7 +314,6 @@
when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
mFragment.mSelectedList.add(device);
setUpFragmentWithShareThenPairIntent(true);
- setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ false);
mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
shadowOf(Looper.getMainLooper()).idle();
@@ -400,7 +326,6 @@
BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
shadowOf(Looper.getMainLooper()).idle();
- verify(device).setMetadata(eq(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS), any());
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mFragment.getActivity()).setResult(eq(Activity.RESULT_OK), captor.capture());
Intent intent = captor.getValue();
@@ -417,35 +342,6 @@
}
@Test
- @Config(shadows = ShadowDialogFragment.class)
- @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
- public void
- onProfileConnectionStateChanged_inSelectedListAndConnected_pairAfterShare_handle() {
- ShadowDialogFragment.reset();
- BluetoothDevice device = spy(mBluetoothDevice);
- when(mCachedBluetoothDevice.getDevice()).thenReturn(device);
- mFragment.mSelectedList.add(device);
- setUpFragmentWithShareThenPairIntent(false);
- setUpAudioSharingStates(/* enabled = */ true, /* needSetTempBondMetadata = */ true);
- mFragment.onDeviceBondStateChanged(mCachedBluetoothDevice, BluetoothDevice.BOND_BONDED);
- shadowOf(Looper.getMainLooper()).idle();
-
- when(mCachedBluetoothDevice.isConnected()).thenReturn(true);
- when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
- when(mCachedBluetoothDevice.isConnectedLeAudioBroadcastAssistantDevice()).thenReturn(true);
- when(mCachedBluetoothDevice.isConnectedVolumeControlDevice()).thenReturn(true);
-
- mFragment.onProfileConnectionStateChanged(mCachedBluetoothDevice,
- BluetoothAdapter.STATE_CONNECTED, BluetoothProfile.LE_AUDIO_BROADCAST_ASSISTANT);
- shadowOf(Looper.getMainLooper()).idle();
-
- verify(device).setMetadata(eq(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS), any());
- verify(mFragment).finish();
-
- ShadowDialogFragment.reset();
- }
-
- @Test
@DisableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_ENABLE_TEMPORARY_BOND_DEVICES_UI})
public void onProfileConnectionStateChanged_deviceNotInSelectedList_doNothing() {
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_B);
@@ -537,38 +433,6 @@
mFragment.mShouldTriggerShareThenPairFlow = mFragment.shouldTriggerShareThenPairFlow();
}
- private void setUpAudioSharingStates(boolean enabled, boolean needSetTempBondMetadata) {
- when(mLocalManager.getProfileManager()).thenReturn(mProfileManager);
- when(mProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
- when(mProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
- when(mLocalManager.getCachedDeviceManager()).thenReturn(mDeviceManager);
- if (!enabled) {
- when(mBroadcast.isEnabled(null)).thenReturn(false);
- } else {
- when(mBroadcast.isEnabled(null)).thenReturn(true);
- when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
- BluetoothDevice device1 = mock(BluetoothDevice.class);
- CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
- when(mDeviceManager.findDevice(device1)).thenReturn(cachedDevice1);
- when(cachedDevice1.getGroupId()).thenReturn(1);
- when(cachedDevice1.getDevice()).thenReturn(device1);
- BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
- when(state.getBroadcastId()).thenReturn(1);
- when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(state));
- if (needSetTempBondMetadata) {
- when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(device1));
- } else {
- BluetoothDevice device2 = mock(BluetoothDevice.class);
- CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
- when(mDeviceManager.findDevice(device2)).thenReturn(cachedDevice2);
- when(cachedDevice2.getGroupId()).thenReturn(2);
- when(cachedDevice2.getDevice()).thenReturn(device2);
- when(mAssistant.getAllConnectedDevices()).thenReturn(
- ImmutableList.of(device1, device2));
- }
- }
- }
-
private static class TestBluetoothDevicePairingDetailBase extends
BluetoothDevicePairingDetailBase {
diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java
index e720038..dfe5171 100644
--- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingReceiverTest.java
@@ -16,28 +16,41 @@
package com.android.settings.connecteddevice.audiosharing;
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED;
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.ACTION_LE_AUDIO_SHARING_STATE_CHANGE;
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.BROADCAST_STATE_OFF;
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.BROADCAST_STATE_ON;
+import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_BLUETOOTH_DEVICE;
import static com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast.EXTRA_LE_AUDIO_SHARING_STATE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
+import android.Manifest;
+import android.app.ActivityManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeBroadcastMetadata;
+import android.bluetooth.BluetoothLeBroadcastReceiveState;
import android.bluetooth.BluetoothStatusCodes;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
import com.android.settings.bluetooth.Utils;
@@ -45,11 +58,16 @@
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowBluetoothUtils;
import com.android.settingslib.R;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
+import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
import com.android.settingslib.flags.Flags;
+import com.google.common.collect.ImmutableList;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -72,6 +90,12 @@
public class AudioSharingReceiverTest {
private static final String ACTION_LE_AUDIO_SHARING_STOP =
"com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_STOP";
+ private static final String ACTION_LE_AUDIO_SHARING_ADD_SOURCE =
+ "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_ADD_SOURCE";
+ private static final String ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF =
+ "com.android.settings.action.BLUETOOTH_LE_AUDIO_SHARING_CANCEL_NOTIF";
+ private static final String EXTRA_NOTIF_ID = "NOTIF_ID";
+ private static final String TEST_DEVICE_NAME = "test";
@Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -83,12 +107,14 @@
private FakeFeatureFactory mFeatureFactory;
@Mock private LocalBluetoothProfileManager mLocalBtProfileManager;
@Mock private LocalBluetoothLeBroadcast mBroadcast;
+ @Mock private LocalBluetoothLeBroadcastAssistant mAssistant;
@Mock private LocalBluetoothManager mLocalBtManager;
+ @Mock private BluetoothDevice mDevice;
@Mock private NotificationManager mNm;
@Before
public void setUp() {
- mContext = RuntimeEnvironment.getApplication();
+ mContext = spy(RuntimeEnvironment.getApplication());
mShadowApplication = Shadow.extract(mContext);
mShadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
@@ -101,6 +127,8 @@
mLocalBluetoothManager = Utils.getLocalBtManager(mContext);
when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBtProfileManager);
when(mLocalBtProfileManager.getLeAudioBroadcastProfile()).thenReturn(mBroadcast);
+ when(mLocalBtProfileManager.getLeAudioBroadcastAssistantProfile()).thenReturn(mAssistant);
+ when(mDevice.getAlias()).thenReturn(TEST_DEVICE_NAME);
mFeatureFactory = FakeFeatureFactory.setupForTest();
}
@@ -130,9 +158,8 @@
}
@Test
+ @DisableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void broadcastReceiver_receiveAudioSharingStateOn_flagOff_doNothing() {
- mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-
Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
intent.setPackage(mContext.getPackageName());
intent.putExtra(EXTRA_LE_AUDIO_SHARING_STATE, BROADCAST_STATE_ON);
@@ -144,8 +171,8 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void broadcastReceiver_receiveAudioSharingStateOn_broadcastDisabled_doNothing() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
@@ -160,9 +187,8 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void broadcastReceiver_receiveAudioSharingStateChangeIntentNoState_doNothing() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-
Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
intent.setPackage(mContext.getPackageName());
AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
@@ -173,9 +199,8 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void broadcastReceiver_receiveAudioSharingStateOn_broadcastEnabled_showNotification() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-
Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
intent.setPackage(mContext.getPackageName());
intent.putExtra(EXTRA_LE_AUDIO_SHARING_STATE, BROADCAST_STATE_ON);
@@ -188,9 +213,9 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void
broadcastReceiver_receiveAudioSharingStateOff_broadcastDisabled_cancelNotification() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
@@ -207,10 +232,9 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void
broadcastReceiver_receiveAudioSharingStateOff_broadcastEnabled_cancelNotification() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
-
Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_STATE_CHANGE);
intent.setPackage(mContext.getPackageName());
intent.putExtra(EXTRA_LE_AUDIO_SHARING_STATE, BROADCAST_STATE_OFF);
@@ -224,8 +248,8 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void broadcastReceiver_receiveAudioSharingStop_broadcastDisabled_cancelNotification() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
@@ -242,8 +266,8 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void broadcastReceiver_receiveAudioSharingStop_notInBroadcast_cancelNotification() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(false);
int broadcastId = 1;
when(mBroadcast.getLatestBroadcastId()).thenReturn(broadcastId);
@@ -261,8 +285,8 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
public void broadcastReceiver_receiveAudioSharingStop_inBroadcast_stopBroadcast() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING);
when(mBroadcast.isEnabled(null)).thenReturn(true);
int broadcastId = 1;
when(mBroadcast.getLatestBroadcastId()).thenReturn(broadcastId);
@@ -281,6 +305,247 @@
ACTION_LE_AUDIO_SHARING_STOP);
}
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingDeviceConnected_broadcastDisabled_doNothing() {
+ mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
+ BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
+
+ setAppInForeground(false);
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mNm, never()).notify(
+ eq(com.android.settings.R.string.share_audio_notification_title),
+ any(Notification.class));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingDeviceConnected_showDialog() {
+ setAppInForeground(true);
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mNm, never()).notify(
+ eq(com.android.settings.R.string.share_audio_notification_title),
+ any(Notification.class));
+ // TODO: verify show dialog once impl complete
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingDeviceConnected_showNotification() {
+ setAppInForeground(false);
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_DEVICE_CONNECTED);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ // TODO: verify no dialog once impl complete
+ verify(mNm).notify(eq(com.android.settings.R.string.share_audio_notification_title),
+ any(Notification.class));
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingAddSource_broadcastDisabled_cancelNotif() {
+ mShadowBluetoothAdapter.setIsLeAudioBroadcastSourceSupported(
+ BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+ anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingAddSource_nullArg_cancelNotif() {
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(any(BluetoothDevice.class),
+ any(BluetoothLeBroadcastMetadata.class), anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingAddSource_notInBroadcast_cancelNotif() {
+ when(mBroadcast.isEnabled(null)).thenReturn(false);
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+ anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingAddSource_notConnected_cancelNotif() {
+ when(mBroadcast.isEnabled(null)).thenReturn(true);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of());
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+ anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingAddSource_invalidGroupId_cancelNotif() {
+ when(mBroadcast.isEnabled(null)).thenReturn(true);
+ CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+ CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+ when(deviceManager.findDevice(mDevice)).thenReturn(cachedDevice);
+ when(cachedDevice.getDevice()).thenReturn(mDevice);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice));
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+ anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX})
+ public void broadcastReceiver_receiveAudioSharingAddSource_alreadyTwoSinks_cancelNotif() {
+ when(mBroadcast.isEnabled(null)).thenReturn(true);
+ when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
+ CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+ CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+ when(deviceManager.findDevice(mDevice)).thenReturn(cachedDevice1);
+ BluetoothDevice device2 = mock(BluetoothDevice.class);
+ CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
+ when(deviceManager.findDevice(device2)).thenReturn(cachedDevice2);
+ when(cachedDevice1.getGroupId()).thenReturn(1);
+ when(cachedDevice1.getDevice()).thenReturn(mDevice);
+ when(cachedDevice1.getName()).thenReturn(TEST_DEVICE_NAME);
+ when(cachedDevice2.getGroupId()).thenReturn(2);
+ when(cachedDevice2.getDevice()).thenReturn(device2);
+ when(cachedDevice2.getName()).thenReturn(TEST_DEVICE_NAME);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice, device2));
+ BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+ when(state.getBroadcastId()).thenReturn(1);
+ when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(state));
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+ anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX})
+ public void broadcastReceiver_receiveAudioSharingAddSource_alreadyHasSource_cancelNotif() {
+ when(mBroadcast.isEnabled(null)).thenReturn(true);
+ when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
+ CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+ CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+ when(deviceManager.findDevice(mDevice)).thenReturn(cachedDevice);
+ when(cachedDevice.getGroupId()).thenReturn(1);
+ when(cachedDevice.getDevice()).thenReturn(mDevice);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice));
+ BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+ when(state.getBroadcastId()).thenReturn(1);
+ when(mAssistant.getAllSources(mDevice)).thenReturn(ImmutableList.of(state));
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant, never()).addSource(eq(mDevice), any(BluetoothLeBroadcastMetadata.class),
+ anyBoolean());
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags({Flags.FLAG_ENABLE_LE_AUDIO_SHARING, Flags.FLAG_AUDIO_SHARING_HYSTERESIS_MODE_FIX})
+ public void broadcastReceiver_receiveAudioSharingAddSource_addSource() {
+ when(mBroadcast.isEnabled(null)).thenReturn(true);
+ when(mBroadcast.getLatestBroadcastId()).thenReturn(1);
+ BluetoothLeBroadcastMetadata metadata = mock(BluetoothLeBroadcastMetadata.class);
+ when(mBroadcast.getLatestBluetoothLeBroadcastMetadata()).thenReturn(metadata);
+ CachedBluetoothDeviceManager deviceManager = mock(CachedBluetoothDeviceManager.class);
+ when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(deviceManager);
+ CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+ when(deviceManager.findDevice(mDevice)).thenReturn(cachedDevice1);
+ BluetoothDevice device2 = mock(BluetoothDevice.class);
+ CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
+ when(deviceManager.findDevice(device2)).thenReturn(cachedDevice2);
+ when(cachedDevice1.getGroupId()).thenReturn(1);
+ when(cachedDevice1.getDevice()).thenReturn(mDevice);
+ when(cachedDevice2.getGroupId()).thenReturn(2);
+ when(cachedDevice2.getDevice()).thenReturn(device2);
+ when(mAssistant.getAllConnectedDevices()).thenReturn(ImmutableList.of(mDevice, device2));
+ BluetoothLeBroadcastReceiveState state = mock(BluetoothLeBroadcastReceiveState.class);
+ when(state.getBroadcastId()).thenReturn(1);
+ when(mAssistant.getAllSources(device2)).thenReturn(ImmutableList.of(state));
+
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_ADD_SOURCE);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_BLUETOOTH_DEVICE, mDevice);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mAssistant).addSource(mDevice, metadata, /* isGroupOp= */ false);
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING)
+ public void broadcastReceiver_receiveAudioSharingCancelNotif_cancel() {
+ Intent intent = new Intent(ACTION_LE_AUDIO_SHARING_CANCEL_NOTIF);
+ intent.setPackage(mContext.getPackageName());
+ intent.putExtra(EXTRA_NOTIF_ID,
+ com.android.settings.R.string.share_audio_notification_title);
+ AudioSharingReceiver audioSharingReceiver = getAudioSharingReceiver(intent);
+ audioSharingReceiver.onReceive(mContext, intent);
+
+ verify(mNm).cancel(com.android.settings.R.string.share_audio_notification_title);
+ }
+
private AudioSharingReceiver getAudioSharingReceiver(Intent intent) {
assertThat(mShadowApplication.hasReceiverForIntent(intent)).isTrue();
List<BroadcastReceiver> receiversForIntent =
@@ -290,4 +555,16 @@
assertThat(broadcastReceiver).isInstanceOf(AudioSharingReceiver.class);
return (AudioSharingReceiver) broadcastReceiver;
}
+
+ private void setAppInForeground(boolean foreground) {
+ ActivityManager activityManager = mock(ActivityManager.class);
+ when(mContext.getSystemService(ActivityManager.class)).thenReturn(activityManager);
+ when(activityManager.getPackageImportance(mContext.getPackageName())).thenReturn(
+ foreground ? ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
+ : ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE);
+ PackageManager packageManager = mock(PackageManager.class);
+ when(mContext.getPackageManager()).thenReturn(packageManager);
+ when(packageManager.checkPermission(Manifest.permission.PACKAGE_USAGE_STATS,
+ mContext.getPackageName())).thenReturn(PackageManager.PERMISSION_GRANTED);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
index 6c29036b..d561395 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryTipsControllerTest.java
@@ -19,6 +19,8 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
@@ -29,30 +31,41 @@
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
import android.os.LocaleList;
+import android.view.View;
-import com.android.settings.R;
import com.android.settings.testutils.BatteryTestUtils;
import com.android.settings.testutils.FakeFeatureFactory;
-import com.android.settings.widget.TipCardPreference;
+import com.android.settingslib.widget.BannerMessagePreference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.RealObject;
+import org.robolectric.shadow.api.Shadow;
import java.util.Locale;
import java.util.TimeZone;
@RunWith(RobolectricTestRunner.class)
+@Config(shadows = BatteryTipsControllerTest.ShadowBannerMessagePreference.class)
public final class BatteryTipsControllerTest {
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
private BatteryTipsController mBatteryTipsController;
- private TipCardPreference mCardPreference;
+ private BannerMessagePreference mCardPreference;
+
+ @Mock Drawable mIconDrawable;
+ @Mock View mView;
@Before
public void setUp() {
@@ -61,12 +74,13 @@
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
mContext = spy(RuntimeEnvironment.application);
+ DatabaseUtils.removeDismissedPowerAnomalyKeys(mContext);
final Resources resources = spy(mContext.getResources());
resources.getConfiguration().setLocales(new LocaleList(new Locale("en_US")));
doReturn(resources).when(mContext).getResources();
mFeatureFactory = FakeFeatureFactory.setupForTest();
mBatteryTipsController = spy(new BatteryTipsController(mContext));
- mCardPreference = new TipCardPreference(mContext);
+ mCardPreference = spy(new BannerMessagePreference(mContext));
mBatteryTipsController.mCardPreference = mCardPreference;
}
@@ -84,18 +98,16 @@
new AnomalyEventWrapper(
mContext,
BatteryTestUtils.createAdaptiveBrightnessAnomalyEvent(true)));
+ when(anomalyEventWrapper.getIconDrawable()).thenReturn(mIconDrawable);
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
mBatteryTipsController.handleBatteryTipsCardUpdated(anomalyEventWrapper, false);
- assertThat(mCardPreference.getTitle())
- .isEqualTo("Turn on adaptive brightness to extend battery life");
- assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo("Got it");
- assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo("View Settings");
- assertThat(mCardPreference.getIconResId()).isEqualTo(R.drawable.ic_battery_tips_lightbulb);
- assertThat(mCardPreference.getTintColorResId()).isEqualTo(R.color.color_accent_selector);
- assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
- assertThat(mCardPreference.getSecondaryButtonVisibility()).isTrue();
+ assertCardPreference(
+ "Turn on adaptive brightness to extend battery life",
+ "View Settings",
+ "Got it",
+ BannerMessagePreference.AttentionLevel.NORMAL);
assertCardButtonActionAndMetrics(anomalyEventWrapper);
}
@@ -105,18 +117,16 @@
spy(
new AnomalyEventWrapper(
mContext, BatteryTestUtils.createScreenTimeoutAnomalyEvent(true)));
+ when(anomalyEventWrapper.getIconDrawable()).thenReturn(mIconDrawable);
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
mBatteryTipsController.handleBatteryTipsCardUpdated(anomalyEventWrapper, false);
- assertThat(mCardPreference.getTitle())
- .isEqualTo("Reduce screen timeout to extend battery life");
- assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo("Got it");
- assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo("View Settings");
- assertThat(mCardPreference.getIconResId()).isEqualTo(R.drawable.ic_battery_tips_lightbulb);
- assertThat(mCardPreference.getTintColorResId()).isEqualTo(R.color.color_accent_selector);
- assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
- assertThat(mCardPreference.getSecondaryButtonVisibility()).isTrue();
+ assertCardPreference(
+ "Reduce screen timeout to extend battery life",
+ "View Settings",
+ "Got it",
+ BannerMessagePreference.AttentionLevel.NORMAL);
assertCardButtonActionAndMetrics(anomalyEventWrapper);
}
@@ -133,17 +143,16 @@
.build();
AnomalyEventWrapper anomalyEventWrapper =
spy(new AnomalyEventWrapper(mContext, anomalyEvent));
+ when(anomalyEventWrapper.getIconDrawable()).thenReturn(mIconDrawable);
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
mBatteryTipsController.handleBatteryTipsCardUpdated(anomalyEventWrapper, false);
- assertThat(mCardPreference.getTitle()).isEqualTo(testTitle);
- assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo("Got it");
- assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo("View Settings");
- assertThat(mCardPreference.getIconResId()).isEqualTo(R.drawable.ic_battery_tips_lightbulb);
- assertThat(mCardPreference.getTintColorResId()).isEqualTo(R.color.color_accent_selector);
- assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
- assertThat(mCardPreference.getSecondaryButtonVisibility()).isTrue();
+ assertCardPreference(
+ testTitle,
+ "View Settings",
+ "Got it",
+ BannerMessagePreference.AttentionLevel.NORMAL);
assertCardButtonActionAndMetrics(anomalyEventWrapper);
}
@@ -151,6 +160,7 @@
public void handleBatteryTipsCardUpdated_appAnomaly_showAnomaly() {
AnomalyEventWrapper anomalyEventWrapper =
spy(new AnomalyEventWrapper(mContext, BatteryTestUtils.createAppAnomalyEvent()));
+ when(anomalyEventWrapper.getIconDrawable()).thenReturn(mIconDrawable);
when(mFeatureFactory.powerUsageFeatureProvider.isBatteryTipsEnabled()).thenReturn(true);
anomalyEventWrapper.setRelatedBatteryDiffEntry(
@@ -159,29 +169,41 @@
() -> mBatteryTipsController.acceptTipsCard());
mBatteryTipsController.handleBatteryTipsCardUpdated(anomalyEventWrapper, true);
- assertThat(mCardPreference.getTitle()).isEqualTo("Chrome used more battery than usual");
- assertThat(mCardPreference.getPrimaryButtonText()).isEqualTo("Got it");
- assertThat(mCardPreference.getSecondaryButtonText()).isEqualTo("Check");
- assertThat(mCardPreference.getIconResId())
- .isEqualTo(R.drawable.ic_battery_tips_warning_icon);
- assertThat(mCardPreference.getTintColorResId())
- .isEqualTo(R.color.color_battery_anomaly_app_warning_selector);
- assertThat(mCardPreference.getPrimaryButtonVisibility()).isTrue();
- assertThat(mCardPreference.getSecondaryButtonVisibility()).isTrue();
- assertThat(mCardPreference.isVisible()).isTrue();
+ assertCardPreference(
+ "Chrome used more battery than usual",
+ "Check",
+ "Got it",
+ BannerMessagePreference.AttentionLevel.MEDIUM);
assertCardButtonActionAndMetrics(anomalyEventWrapper);
}
+ private void assertCardPreference(
+ final String title,
+ final String positiveBtnText,
+ final String negativeBtnText,
+ BannerMessagePreference.AttentionLevel attentionLevel) {
+ verify(mCardPreference).setTitle(eq(title));
+ verify(mCardPreference).setPositiveButtonText(eq(positiveBtnText));
+ verify(mCardPreference).setNegativeButtonText(eq(negativeBtnText));
+ verify(mCardPreference).setIcon(mIconDrawable);
+ verify(mCardPreference).setAttentionLevel(attentionLevel);
+ verify(mCardPreference).setPositiveButtonVisible(true);
+ verify(mCardPreference).setNegativeButtonVisible(true);
+ assertThat(mCardPreference.isVisible()).isTrue();
+ }
+
private void assertCardButtonActionAndMetrics(final AnomalyEventWrapper anomalyEventWrapper) {
when(anomalyEventWrapper.updateSystemSettingsIfAvailable()).thenReturn(true);
final int powerAnomalyKeyNumber = anomalyEventWrapper.getAnomalyKeyNumber();
assertCardMetrics(SettingsEnums.ACTION_BATTERY_TIPS_CARD_SHOW, powerAnomalyKeyNumber);
assertThat(mCardPreference.isVisible()).isTrue();
+ final ShadowBannerMessagePreference shadowPreference = Shadow.extract(mCardPreference);
// Check accept button action
mCardPreference.setVisible(true);
- mCardPreference.getSecondaryButtonAction().invoke();
+ clearInvocations(mFeatureFactory.metricsFeatureProvider);
+ shadowPreference.getPositiveButtonOnClickListener().onClick(mView);
assertCardMetrics(SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, powerAnomalyKeyNumber);
assertThat(mCardPreference.isVisible()).isFalse();
final boolean isAppAnomalyCard = powerAnomalyKeyNumber > 1;
@@ -190,7 +212,8 @@
// Check reject button action
mCardPreference.setVisible(true);
- mCardPreference.getPrimaryButtonAction().invoke();
+ clearInvocations(mFeatureFactory.metricsFeatureProvider);
+ shadowPreference.getNegativeButtonOnClickListener().onClick(mView);
assertCardMetrics(SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, powerAnomalyKeyNumber);
assertThat(mCardPreference.isVisible()).isFalse();
}
@@ -204,4 +227,37 @@
BatteryTipsController.ANOMALY_KEY,
powerAnomalyKeyNumber);
}
+
+ @Implements(BannerMessagePreference.class)
+ public static class ShadowBannerMessagePreference {
+
+ @RealObject protected BannerMessagePreference mRealBannerMessagePreference;
+
+ private View.OnClickListener mPositiveButtonOnClickListener;
+ private View.OnClickListener mNegativeButtonOnClickListener;
+
+ /** Shadow implementation of setPositiveButtonOnClickListener */
+ @Implementation
+ public BannerMessagePreference setPositiveButtonOnClickListener(
+ View.OnClickListener listener) {
+ mPositiveButtonOnClickListener = listener;
+ return mRealBannerMessagePreference;
+ }
+
+ /** Shadow implementation of setNegativeButtonOnClickListener */
+ @Implementation
+ public BannerMessagePreference setNegativeButtonOnClickListener(
+ View.OnClickListener listener) {
+ mNegativeButtonOnClickListener = listener;
+ return mRealBannerMessagePreference;
+ }
+
+ View.OnClickListener getPositiveButtonOnClickListener() {
+ return mPositiveButtonOnClickListener;
+ }
+
+ View.OnClickListener getNegativeButtonOnClickListener() {
+ return mNegativeButtonOnClickListener;
+ }
+ }
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
index 887a324..5149bf4 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/InterruptionFilterPreferenceControllerTest.java
@@ -130,7 +130,7 @@
verify(mBackend).updateMode(captor.capture());
assertThat(captor.getValue().getPolicy().getPriorityCategoryAlarms())
.isEqualTo(STATE_DISALLOW);
- assertThat(captor.getValue().getRule().getInterruptionFilter())
+ assertThat(captor.getValue().getInterruptionFilter())
.isEqualTo(INTERRUPTION_FILTER_PRIORITY);
}
@@ -162,7 +162,7 @@
verify(mBackend).updateMode(captor.capture());
assertThat(captor.getValue().getPolicy().getPriorityCategoryAlarms())
.isEqualTo(STATE_DISALLOW);
- assertThat(captor.getValue().getRule().getInterruptionFilter())
+ assertThat(captor.getValue().getInterruptionFilter())
.isEqualTo(INTERRUPTION_FILTER_ALL);
}
}
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java
index 1140238..ad4112d 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeAppsPreferenceControllerTest.java
@@ -183,7 +183,7 @@
// NONE is not actually propagated to the backend as an interruption filter;
// the filter is set to priority, and sounds and visual effects are disallowed.
// See AbstractZenModePreferenceController.
- assertThat(captor.getValue().getRule().getInterruptionFilter())
+ assertThat(captor.getValue().getInterruptionFilter())
.isEqualTo(INTERRUPTION_FILTER_PRIORITY);
// After screen is refreshed, NONE is now checked; others are unchecked.
@@ -217,7 +217,7 @@
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
verify(mBackend).updateMode(captor.capture());
// Checks the policy value for PRIORITY is propagated to the backend.
- assertThat(captor.getValue().getRule().getInterruptionFilter())
+ assertThat(captor.getValue().getInterruptionFilter())
.isEqualTo(INTERRUPTION_FILTER_PRIORITY);
// After screen is refreshed, PRIORITY is now checked; others are unchecked.
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentTest.java
index cb853bb..4a0d8d4 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeEditNameIconFragmentTest.java
@@ -124,7 +124,7 @@
verify(mBackend).updateMode(captor.capture());
ZenMode savedMode = captor.getValue();
assertThat(savedMode.getName()).isEqualTo("A newer name");
- assertThat(savedMode.getRule().getIconResId()).isEqualTo(
+ assertThat(savedMode.getIconKey().resId()).isEqualTo(
R.drawable.ic_zen_mode_type_theater);
assertThat(mActivity.isFinishing()).isTrue();
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java
index c949fb8..abd0b67 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeExitAtAlarmPreferenceControllerTest.java
@@ -34,6 +34,7 @@
import com.android.settingslib.notification.modes.TestModeBuilder;
import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
import com.android.settingslib.notification.modes.ZenModesBackend;
import org.junit.Before;
@@ -89,7 +90,7 @@
// Now update state after changing exitAtAlarm
scheduleInfo.exitAtAlarm = true;
- mode.getRule().setConditionId(ZenModeConfig.toScheduleConditionId(scheduleInfo));
+ mode.setCustomModeConditionId(mContext, ZenModeConfig.toScheduleConditionId(scheduleInfo));
// now can just call updateState
mPrefController.updateState(preference, mode);
@@ -117,8 +118,8 @@
mPrefController.onPreferenceChange(preference, false);
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
verify(mBackend).updateMode(captor.capture());
- ZenModeConfig.ScheduleInfo newSchedule = ZenModeConfig.tryParseScheduleConditionId(
- captor.getValue().getRule().getConditionId());
+ ZenModeConfig.ScheduleInfo newSchedule = ZenModeSchedules.getTimeSchedule(
+ captor.getValue());
assertThat(newSchedule.exitAtAlarm).isFalse();
// other properties remain the same
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java
index f0c2369..512e8af 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetCalendarPreferenceControllerTest.java
@@ -41,6 +41,7 @@
import com.android.settingslib.notification.modes.TestModeBuilder;
import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
import com.android.settingslib.notification.modes.ZenModesBackend;
import org.junit.Before;
@@ -102,10 +103,10 @@
// apply event mode updater to existing mode
ZenMode out = mPrefController.updateEventMode(eventInfo).apply(mode);
- assertThat(out.getRule().getOwner()).isEqualTo(ZenModeConfig.getEventConditionProvider());
- assertThat(out.getRule().getConditionId()).isEqualTo(
- ZenModeConfig.toEventConditionId(eventInfo));
- assertThat(out.getRule().getTriggerDescription()).isEqualTo("My events");
+ assertThat(ZenModeSchedules.getCalendarSchedule(out)).isEqualTo(eventInfo);
+ assertThat(out.getOwner().conditionProvider()).isEqualTo(
+ ZenModeConfig.getEventConditionProvider());
+ assertThat(out.getTriggerDescription()).isEqualTo("My events");
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java
index b446d71..0ae37b6 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeSetSchedulePreferenceControllerTest.java
@@ -38,6 +38,7 @@
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.notification.modes.TestModeBuilder;
import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
import com.android.settingslib.notification.modes.ZenModesBackend;
import org.junit.Before;
@@ -92,11 +93,10 @@
scheduleInfo.endHour = 2;
ZenMode out = mPrefController.updateScheduleMode(scheduleInfo).apply(mode);
- assertThat(out.getRule().getConditionId())
- .isEqualTo(ZenModeConfig.toScheduleConditionId(scheduleInfo));
- assertThat(out.getRule().getTriggerDescription()).isNotEmpty();
- assertThat(out.getRule().getOwner()).isEqualTo(
+ assertThat(ZenModeSchedules.getTimeSchedule(out)).isEqualTo(scheduleInfo);
+ assertThat(out.getOwner().conditionProvider()).isEqualTo(
ZenModeConfig.getScheduleConditionProvider());
+ assertThat(out.getTriggerDescription()).isNotEmpty();
}
@Test
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java
index 0a8e400..b8f8ff3 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerAddPreferenceControllerTest.java
@@ -44,6 +44,7 @@
import com.android.settings.dashboard.DashboardFragment;
import com.android.settingslib.notification.modes.TestModeBuilder;
import com.android.settingslib.notification.modes.ZenMode;
+import com.android.settingslib.notification.modes.ZenModeSchedules;
import com.android.settingslib.notification.modes.ZenModesBackend;
import org.junit.Before;
@@ -168,9 +169,9 @@
verify(mBackend).updateMode(captor.capture());
ZenMode updatedMode = captor.getValue();
assertThat(updatedMode.getType()).isEqualTo(TYPE_SCHEDULE_TIME);
- assertThat(updatedMode.getRule().getConditionId()).isEqualTo(scheduleUri);
- assertThat(updatedMode.getRule().getTriggerDescription()).isNotEmpty();
- assertThat(updatedMode.getRule().getOwner()).isEqualTo(
+ assertThat(ZenModeSchedules.getTimeSchedule(updatedMode)).isEqualTo(scheduleInfo);
+ assertThat(updatedMode.getTriggerDescription()).isNotEmpty();
+ assertThat(updatedMode.getOwner().conditionProvider()).isEqualTo(
ZenModeConfig.getScheduleConditionProvider());
}
}
diff --git a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
index 6e6485e..b5d4203 100644
--- a/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/notification/modes/ZenModeTriggerUpdatePreferenceControllerTest.java
@@ -161,7 +161,7 @@
assertThat(mPreference.getCheckedState()).isFalse();
// Now with the rule enabled
- zenMode.getRule().setEnabled(true);
+ zenMode.setEnabled(true);
mController.updateZenMode(mPreference, zenMode);
assertThat(mPreference.getCheckedState()).isTrue();
}
@@ -189,7 +189,7 @@
// Verify the backend got asked to update the mode to be enabled
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
verify(mBackend).updateMode(captor.capture());
- assertThat(captor.getValue().getRule().isEnabled()).isTrue();
+ assertThat(captor.getValue().isEnabled()).isTrue();
assertThat(ShadowAlertDialog.getLatestAlertDialog().isShowing()).isFalse();
}
@@ -216,7 +216,7 @@
// Verify the backend got asked to update the mode to be disabled
ArgumentCaptor<ZenMode> captor = ArgumentCaptor.forClass(ZenMode.class);
verify(mBackend).updateMode(captor.capture());
- assertThat(captor.getValue().getRule().isEnabled()).isFalse();
+ assertThat(captor.getValue().isEnabled()).isFalse();
assertThat(ShadowAlertDialog.getLatestAlertDialog().isShowing()).isFalse();
}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
index d985ee5..99b3acc 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiConfigController2Test.java
@@ -194,15 +194,6 @@
}
@Test
- public void isSubmittable_noSSID_shouldReturnFalse() {
- createController(mWifiEntry, WifiConfigUiBase2.MODE_CONNECT, false);
- final TextView ssid = mView.findViewById(R.id.ssid);
- assertThat(ssid).isNotNull();
- ssid.setText("");
- assertThat(mController.isSubmittable()).isFalse();
- }
-
- @Test
public void isSubmittable_longPsk_shouldReturnFalse() {
createController(mWifiEntry, WifiConfigUiBase2.MODE_CONNECT, false);
final TextView password = mView.findViewById(R.id.password);
@@ -1048,6 +1039,24 @@
verify(mController.mEapAnonymousView, never()).setText(any(String.class));
}
+ @Test
+ public void canFinish_ssidIsEmpty_returnFalse() {
+ createController(null, WifiConfigUiBase2.MODE_CONNECT, false);
+ TextView ssid = mView.findViewById(R.id.ssid);
+ ssid.setText("");
+
+ assertThat(mController.canFinish()).isFalse();
+ }
+
+ @Test
+ public void canFinish_ssidIsGood_returnTrue() {
+ createController(null, WifiConfigUiBase2.MODE_CONNECT, false);
+ TextView ssid = mView.findViewById(R.id.ssid);
+ ssid.setText(GOOD_SSID);
+
+ assertThat(mController.canFinish()).isTrue();
+ }
+
private void setUpModifyingSavedCertificateConfigController(String savedCaCertificate,
String savedUserCertificate) {
final WifiConfiguration mockWifiConfig = spy(new WifiConfiguration());
diff --git a/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceControllerTest.kt
index 5d68f98..67659ba 100644
--- a/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceControllerTest.kt
+++ b/tests/spa_unit/src/com/android/settings/deviceinfo/simstatus/SimEidPreferenceControllerTest.kt
@@ -17,17 +17,23 @@
package com.android.settings.deviceinfo.simstatus
import android.content.Context
+import android.os.UserManager
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.settings.core.BasePreferenceController
import com.android.settings.network.SubscriptionUtil
+import com.android.settingslib.Utils
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.MockitoSession
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.stub
import org.mockito.kotlin.whenever
import org.mockito.quality.Strictness
@@ -35,7 +41,12 @@
class SimEidPreferenceControllerTest {
private lateinit var mockSession: MockitoSession
- private val context: Context = ApplicationProvider.getApplicationContext()
+ private val mockUserManager = mock<UserManager>()
+
+ private val context: Context =
+ spy(ApplicationProvider.getApplicationContext()) {
+ on { getSystemService(UserManager::class.java) } doReturn mockUserManager
+ }
private val controller = SimEidPreferenceController(context, TEST_KEY)
@@ -44,8 +55,16 @@
mockSession = ExtendedMockito.mockitoSession()
.initMocks(this)
.mockStatic(SubscriptionUtil::class.java)
+ .mockStatic(Utils::class.java)
.strictness(Strictness.LENIENT)
.startMocking()
+
+ // By default, available
+ whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
+ whenever(Utils.isWifiOnly(context)).thenReturn(false)
+ mockUserManager.stub {
+ on { isAdminUser } doReturn true
+ }
}
@After
@@ -54,20 +73,35 @@
}
@Test
- fun getAvailabilityStatus_isSimHardwareVisible() {
- whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(true)
-
+ fun getAvailabilityStatus_simHardwareVisible_userAdmin_notWifiOnly_displayed() {
+ // Use defaults from setup()
val availabilityStatus = controller.availabilityStatus
-
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.AVAILABLE)
}
@Test
- fun getAvailabilityStatus_notSimHardwareVisible() {
+ fun getAvailabilityStatus_notSimHardwareVisible_userAdmin_notWifiOnly_notDisplayed() {
whenever(SubscriptionUtil.isSimHardwareVisible(context)).thenReturn(false)
val availabilityStatus = controller.availabilityStatus
+ assertThat(availabilityStatus).isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE)
+ }
+ @Test
+ fun getAvailabilityStatus_simHardwareVisible_notUserAdmin_notWifiOnly_notDisplayed() {
+ mockUserManager.stub {
+ on { isAdminUser } doReturn false
+ }
+
+ val availabilityStatus = controller.availabilityStatus
+ assertThat(availabilityStatus).isEqualTo(BasePreferenceController.DISABLED_FOR_USER)
+ }
+
+ @Test
+ fun getAvailabilityStatus_simHardwareVisible_userAdmin_wifiOnly_notDisplayed() {
+ whenever(Utils.isWifiOnly(context)).thenReturn(true)
+
+ val availabilityStatus = controller.availabilityStatus
assertThat(availabilityStatus).isEqualTo(BasePreferenceController.UNSUPPORTED_ON_DEVICE)
}
diff --git a/tests/unit/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceControllerTest.java b/tests/unit/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceControllerTest.java
index 6318c9c..300d028 100644
--- a/tests/unit/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/deviceinfo/TopLevelStoragePreferenceControllerTest.java
@@ -86,7 +86,7 @@
when(mController.getStorageManagerVolumeProvider())
.thenReturn(mStorageManagerVolumeProvider);
final String percentage = NumberFormat.getPercentInstance().format(1);
- final String freeSpace = Formatter.formatFileSize(mContext, 0);
+ final String[] freeSpace = Formatter.formatFileSize(mContext, 0).split(" ");
final Preference preference = new Preference(mContext);
// Wait for asynchronous thread to finish, otherwise test will flake.
@@ -103,6 +103,6 @@
// the background thread.
TimeUnit.SECONDS.sleep(5);
assertThat(preference.getSummary()).isEqualTo(ResourcesUtils.getResourcesString(
- mContext, "storage_summary", percentage, freeSpace));
+ mContext, "storage_summary", percentage, freeSpace[0], freeSpace[1]));
}
}