Snap for 12829911 from f2f9874122 to 25Q2-release
Change-Id: I57ad032a7adfdc5427f643e82533893b0fe69274
This commit is contained in:
@@ -4459,6 +4459,19 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity android:name=".security.ActionDisabledByAdvancedProtectionDialog"
|
||||||
|
android:theme="@style/Theme.AlertDialog"
|
||||||
|
android:taskAffinity="com.android.settings.security"
|
||||||
|
android:excludeFromRecents="true"
|
||||||
|
android:exported="false"
|
||||||
|
android:launchMode="singleTop"
|
||||||
|
android:featureFlag="android.security.aapm_api">
|
||||||
|
<intent-filter android:priority="1">
|
||||||
|
<action android:name="android.security.advancedprotection.action.SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="Settings$ManageExternalStorageActivity"
|
android:name="Settings$ManageExternalStorageActivity"
|
||||||
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
android:knownActivityEmbeddingCerts="@array/config_known_host_certs"
|
||||||
@@ -5440,7 +5453,7 @@
|
|||||||
</service>
|
</service>
|
||||||
|
|
||||||
<receiver android:name="com.android.settings.connecteddevice.audiosharing.AudioSharingReceiver"
|
<receiver android:name="com.android.settings.connecteddevice.audiosharing.AudioSharingReceiver"
|
||||||
android:exported="false">
|
android:exported="true">
|
||||||
<intent-filter>
|
<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_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_STOP" />
|
||||||
|
|||||||
@@ -14,15 +14,217 @@
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<inset xmlns:android="http://schemas.android.com/apk/res/android"
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:insetBottom="@dimen/pointer_fill_style_circle_offset"
|
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" >
|
||||||
android:insetLeft="@dimen/pointer_fill_style_circle_offset"
|
<item
|
||||||
android:insetRight="@dimen/pointer_fill_style_circle_offset"
|
android:state_hovered="true"
|
||||||
android:insetTop="@dimen/pointer_fill_style_circle_offset">
|
android:state_selected="true">
|
||||||
<shape android:shape="oval">
|
<layer-list>
|
||||||
<size
|
<item
|
||||||
android:width="@dimen/pointer_fill_style_circle_inner_diameter"
|
android:top="@dimen/pointer_fill_style_circle_background_outline_offset"
|
||||||
android:height="@dimen/pointer_fill_style_circle_inner_diameter" />
|
android:left="@dimen/pointer_fill_style_circle_background_outline_offset"
|
||||||
<solid android:color="@android:color/white" />
|
android:bottom="@dimen/pointer_fill_style_circle_background_outline_offset"
|
||||||
</shape>
|
android:right="@dimen/pointer_fill_style_circle_background_outline_offset">
|
||||||
</inset>
|
<shape android:shape="rectangle">
|
||||||
|
<corners
|
||||||
|
android:radius="@dimen/pointer_fill_style_circle_background_corner_radius" />
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_background_outer_diameter_less_stroke"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_background_outer_diameter_less_stroke" />
|
||||||
|
<stroke
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_background_selected_outline_stroke"
|
||||||
|
android:color="@androidprv:color/materialColorSecondary" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:top="@dimen/pointer_fill_style_circle_background_offset"
|
||||||
|
android:left="@dimen/pointer_fill_style_circle_background_offset"
|
||||||
|
android:bottom="@dimen/pointer_fill_style_circle_background_offset"
|
||||||
|
android:right="@dimen/pointer_fill_style_circle_background_offset">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="@dimen/pointer_fill_style_circle_background_corner_inner_radius" />
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_background_outer_diameter_selected"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_background_outer_diameter_selected" />
|
||||||
|
<solid
|
||||||
|
android:color="@color/pointer_fill_hovered_color" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:id="@+id/tintableCircleHoveredSelected"
|
||||||
|
android:top="@dimen/pointer_fill_style_circle_offset_selected"
|
||||||
|
android:left="@dimen/pointer_fill_style_circle_offset_selected"
|
||||||
|
android:bottom="@dimen/pointer_fill_style_circle_offset_selected"
|
||||||
|
android:right="@dimen/pointer_fill_style_circle_offset_selected">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_diameter"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_diameter" />
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:top="@dimen/pointer_fill_style_circle_outline_offset_selected"
|
||||||
|
android:left="@dimen/pointer_fill_style_circle_outline_offset_selected"
|
||||||
|
android:bottom="@dimen/pointer_fill_style_circle_outline_offset_selected"
|
||||||
|
android:right="@dimen/pointer_fill_style_circle_outline_offset_selected">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_outline_diameter"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_outline_diameter" />
|
||||||
|
<stroke
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_outline_stroke"
|
||||||
|
android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:gravity="center"
|
||||||
|
android:width="@dimen/pointer_fill_style_checkmark_size"
|
||||||
|
android:height="@dimen/pointer_fill_style_checkmark_size"
|
||||||
|
android:drawable="@drawable/pointer_fill_check_24dp" />
|
||||||
|
</layer-list>
|
||||||
|
</item>
|
||||||
|
<item android:state_selected="true">
|
||||||
|
<layer-list>
|
||||||
|
<item
|
||||||
|
android:top="@dimen/pointer_fill_style_circle_background_outline_offset"
|
||||||
|
android:left="@dimen/pointer_fill_style_circle_background_outline_offset"
|
||||||
|
android:bottom="@dimen/pointer_fill_style_circle_background_outline_offset"
|
||||||
|
android:right="@dimen/pointer_fill_style_circle_background_outline_offset">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="@dimen/pointer_fill_style_circle_background_corner_radius" />
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_background_outer_diameter_less_stroke"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_background_outer_diameter_less_stroke" />
|
||||||
|
<stroke
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_background_selected_outline_stroke"
|
||||||
|
android:color="@androidprv:color/materialColorSecondary" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:top="@dimen/pointer_fill_style_circle_background_offset"
|
||||||
|
android:left="@dimen/pointer_fill_style_circle_background_offset"
|
||||||
|
android:bottom="@dimen/pointer_fill_style_circle_background_offset"
|
||||||
|
android:right="@dimen/pointer_fill_style_circle_background_offset">
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="@dimen/pointer_fill_style_circle_background_corner_inner_radius" />
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_background_outer_diameter_selected"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_background_outer_diameter_selected" />
|
||||||
|
<solid android:color="@androidprv:color/materialColorSurfaceBright" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:id="@+id/tintableCircleSelected"
|
||||||
|
android:top="@dimen/pointer_fill_style_circle_offset_selected"
|
||||||
|
android:left="@dimen/pointer_fill_style_circle_offset_selected"
|
||||||
|
android:bottom="@dimen/pointer_fill_style_circle_offset_selected"
|
||||||
|
android:right="@dimen/pointer_fill_style_circle_offset_selected">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_diameter"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_diameter" />
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:top="@dimen/pointer_fill_style_circle_outline_offset_selected"
|
||||||
|
android:left="@dimen/pointer_fill_style_circle_outline_offset_selected"
|
||||||
|
android:bottom="@dimen/pointer_fill_style_circle_outline_offset_selected"
|
||||||
|
android:right="@dimen/pointer_fill_style_circle_outline_offset_selected">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_outline_diameter"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_outline_diameter" />
|
||||||
|
<stroke
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_outline_stroke"
|
||||||
|
android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:gravity="center"
|
||||||
|
android:width="@dimen/pointer_fill_style_checkmark_size"
|
||||||
|
android:height="@dimen/pointer_fill_style_checkmark_size"
|
||||||
|
android:drawable="@drawable/pointer_fill_check_24dp" />
|
||||||
|
</layer-list>
|
||||||
|
</item>
|
||||||
|
<item android:state_hovered="true">
|
||||||
|
<layer-list>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="@dimen/pointer_fill_style_circle_background_corner_radius" />
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_background_outer_diameter" />
|
||||||
|
<solid android:color="@color/pointer_fill_hovered_color" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:id="@+id/tintableCircleHovered"
|
||||||
|
android:top="@dimen/pointer_fill_style_circle_offset"
|
||||||
|
android:left="@dimen/pointer_fill_style_circle_offset"
|
||||||
|
android:bottom="@dimen/pointer_fill_style_circle_offset"
|
||||||
|
android:right="@dimen/pointer_fill_style_circle_offset">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_diameter"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_diameter" />
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:top="@dimen/pointer_fill_style_circle_outline_offset"
|
||||||
|
android:left="@dimen/pointer_fill_style_circle_outline_offset"
|
||||||
|
android:bottom="@dimen/pointer_fill_style_circle_outline_offset"
|
||||||
|
android:right="@dimen/pointer_fill_style_circle_outline_offset">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_outline_diameter"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_outline_diameter" />
|
||||||
|
<stroke
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_outline_stroke"
|
||||||
|
android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
|
</item>
|
||||||
|
<item><!-- default state -->
|
||||||
|
<layer-list>
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="@dimen/pointer_fill_style_circle_background_corner_radius" />
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_background_outer_diameter" />
|
||||||
|
<solid android:color="@androidprv:color/materialColorSurfaceBright" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:id="@+id/tintableCircleDefault"
|
||||||
|
android:top="@dimen/pointer_fill_style_circle_offset"
|
||||||
|
android:left="@dimen/pointer_fill_style_circle_offset"
|
||||||
|
android:bottom="@dimen/pointer_fill_style_circle_offset"
|
||||||
|
android:right="@dimen/pointer_fill_style_circle_offset">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_diameter"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_diameter" />
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:top="@dimen/pointer_fill_style_circle_outline_offset"
|
||||||
|
android:left="@dimen/pointer_fill_style_circle_outline_offset"
|
||||||
|
android:bottom="@dimen/pointer_fill_style_circle_outline_offset"
|
||||||
|
android:right="@dimen/pointer_fill_style_circle_outline_offset">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<size
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_outline_diameter"
|
||||||
|
android:height="@dimen/pointer_fill_style_circle_outline_diameter" />
|
||||||
|
<stroke
|
||||||
|
android:width="@dimen/pointer_fill_style_circle_outline_stroke"
|
||||||
|
android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
||||||
|
</item>
|
||||||
|
</selector>
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
Copyright 2024 The Android Open Source Project
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
||||||
-->
|
|
||||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<item android:state_selected="true" android:state_hovered="true">
|
|
||||||
<layer-list>
|
|
||||||
<item>
|
|
||||||
<shape android:shape="oval">
|
|
||||||
<size android:width="@dimen/pointer_fill_style_circle_hover_selected_diameter"
|
|
||||||
android:height="@dimen/pointer_fill_style_circle_hover_selected_diameter" />
|
|
||||||
<stroke android:width="@dimen/pointer_fill_style_shape_hovered_stroke"
|
|
||||||
android:color="@color/pointer_fill_outline_color" />
|
|
||||||
</shape>
|
|
||||||
</item>
|
|
||||||
<item
|
|
||||||
android:top="@dimen/pointer_fill_style_checkmark_hovered_padding"
|
|
||||||
android:left="@dimen/pointer_fill_style_checkmark_hovered_padding"
|
|
||||||
android:bottom="@dimen/pointer_fill_style_checkmark_hovered_padding"
|
|
||||||
android:right="@dimen/pointer_fill_style_checkmark_hovered_padding"
|
|
||||||
android:drawable="@drawable/pointer_fill_check_24dp" />
|
|
||||||
</layer-list>
|
|
||||||
</item>
|
|
||||||
<item android:state_selected="true">
|
|
||||||
<layer-list>
|
|
||||||
<item>
|
|
||||||
<inset android:insetTop="@dimen/pointer_fill_style_circle_selected_offset"
|
|
||||||
android:insetLeft="@dimen/pointer_fill_style_circle_selected_offset"
|
|
||||||
android:insetBottom="@dimen/pointer_fill_style_circle_selected_offset"
|
|
||||||
android:insetRight="@dimen/pointer_fill_style_circle_selected_offset">
|
|
||||||
<shape android:shape="oval">
|
|
||||||
<size android:width="@dimen/pointer_fill_style_circle_selected_diameter"
|
|
||||||
android:height="@dimen/pointer_fill_style_circle_selected_diameter" />
|
|
||||||
<stroke android:width="@dimen/pointer_fill_style_shape_selected_stroke"
|
|
||||||
android:color="@color/pointer_fill_outline_color" />
|
|
||||||
</shape>
|
|
||||||
</inset>
|
|
||||||
</item>
|
|
||||||
<item
|
|
||||||
android:top="@dimen/pointer_fill_style_checkmark_selected_padding"
|
|
||||||
android:left="@dimen/pointer_fill_style_checkmark_selected_padding"
|
|
||||||
android:bottom="@dimen/pointer_fill_style_checkmark_selected_padding"
|
|
||||||
android:right="@dimen/pointer_fill_style_checkmark_selected_padding"
|
|
||||||
android:drawable="@drawable/pointer_fill_check_24dp" />
|
|
||||||
</layer-list>
|
|
||||||
</item>
|
|
||||||
<item android:state_hovered="true">
|
|
||||||
<shape android:shape="oval">
|
|
||||||
<size android:width="@dimen/pointer_fill_style_circle_hover_diameter"
|
|
||||||
android:height="@dimen/pointer_fill_style_circle_hover_diameter" />
|
|
||||||
<stroke android:width="@dimen/pointer_fill_style_shape_hovered_stroke"
|
|
||||||
android:color="@color/pointer_fill_outline_color" />
|
|
||||||
</shape>
|
|
||||||
</item>
|
|
||||||
</selector>
|
|
||||||
@@ -53,6 +53,7 @@
|
|||||||
android:layout_height="@dimen/chartview_layout_height"
|
android:layout_height="@dimen/chartview_layout_height"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_marginBottom="16dp"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
|
android:alpha="0"
|
||||||
android:contentDescription="@string/hourly_battery_usage_chart"
|
android:contentDescription="@string/hourly_battery_usage_chart"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
settings:textColor="?android:attr/textColorSecondary" />
|
settings:textColor="?android:attr/textColorSecondary" />
|
||||||
|
|||||||
@@ -42,7 +42,6 @@
|
|||||||
android:layout_height="@dimen/pointer_fill_container_height"
|
android:layout_height="@dimen/pointer_fill_container_height"
|
||||||
android:layout_marginBottom="@dimen/pointer_fill_style_circle_padding"
|
android:layout_marginBottom="@dimen/pointer_fill_style_circle_padding"
|
||||||
android:layout_marginTop="@dimen/pointer_fill_style_circle_padding"
|
android:layout_marginTop="@dimen/pointer_fill_style_circle_padding"
|
||||||
android:background="@drawable/pointer_icon_fill_container_background"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:paddingTop="@dimen/pointer_fill_style_container_padding"
|
android:paddingTop="@dimen/pointer_fill_style_container_padding"
|
||||||
android:paddingBottom="@dimen/pointer_fill_style_container_padding">
|
android:paddingBottom="@dimen/pointer_fill_style_container_padding">
|
||||||
@@ -53,19 +52,18 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:layout_weight="4" />
|
android:layout_weight="1" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/button_black"
|
android:id="@+id/button_black"
|
||||||
android:layout_width="@dimen/pointer_fill_style_circle_diameter"
|
android:layout_width="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:layout_height="@dimen/pointer_fill_style_circle_diameter"
|
android:layout_height="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:maxWidth="@dimen/pointer_fill_style_circle_diameter"
|
android:maxWidth="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:contentDescription="@string/pointer_fill_style_black_button"
|
android:contentDescription="@string/pointer_fill_style_black_button"
|
||||||
android:scaleType="center"
|
android:scaleType="center"
|
||||||
android:background="@drawable/pointer_icon_fill_color_background"
|
android:src="@drawable/pointer_icon_fill_color_background" />
|
||||||
android:src="@drawable/pointer_icon_fill_color_foreground" />
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@@ -73,19 +71,18 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:layout_weight="3" />
|
android:layout_weight="1" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/button_green"
|
android:id="@+id/button_green"
|
||||||
android:layout_width="@dimen/pointer_fill_style_circle_diameter"
|
android:layout_width="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:layout_height="@dimen/pointer_fill_style_circle_diameter"
|
android:layout_height="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:maxWidth="@dimen/pointer_fill_style_circle_diameter"
|
android:maxWidth="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:contentDescription="@string/pointer_fill_style_green_button"
|
android:contentDescription="@string/pointer_fill_style_green_button"
|
||||||
android:scaleType="center"
|
android:scaleType="center"
|
||||||
android:background="@drawable/pointer_icon_fill_color_background"
|
android:src="@drawable/pointer_icon_fill_color_background" />
|
||||||
android:src="@drawable/pointer_icon_fill_color_foreground" />
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@@ -93,19 +90,18 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:layout_weight="3" />
|
android:layout_weight="1" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/button_red"
|
android:id="@+id/button_red"
|
||||||
android:layout_width="@dimen/pointer_fill_style_circle_diameter"
|
android:layout_width="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:layout_height="@dimen/pointer_fill_style_circle_diameter"
|
android:layout_height="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:maxWidth="@dimen/pointer_fill_style_circle_diameter"
|
android:maxWidth="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:contentDescription="@string/pointer_fill_style_red_button"
|
android:contentDescription="@string/pointer_fill_style_red_button"
|
||||||
android:scaleType="center"
|
android:scaleType="center"
|
||||||
android:background="@drawable/pointer_icon_fill_color_background"
|
android:src="@drawable/pointer_icon_fill_color_background" />
|
||||||
android:src="@drawable/pointer_icon_fill_color_foreground" />
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@@ -113,19 +109,18 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:layout_weight="3" />
|
android:layout_weight="1" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/button_pink"
|
android:id="@+id/button_pink"
|
||||||
android:layout_width="@dimen/pointer_fill_style_circle_diameter"
|
android:layout_width="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:layout_height="@dimen/pointer_fill_style_circle_diameter"
|
android:layout_height="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:maxWidth="@dimen/pointer_fill_style_circle_diameter"
|
android:maxWidth="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:contentDescription="@string/pointer_fill_style_pink_button"
|
android:contentDescription="@string/pointer_fill_style_pink_button"
|
||||||
android:scaleType="center"
|
android:scaleType="center"
|
||||||
android:background="@drawable/pointer_icon_fill_color_background"
|
android:src="@drawable/pointer_icon_fill_color_background" />
|
||||||
android:src="@drawable/pointer_icon_fill_color_foreground" />
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@@ -133,19 +128,18 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:layout_weight="3" />
|
android:layout_weight="1" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/button_blue"
|
android:id="@+id/button_blue"
|
||||||
android:layout_width="@dimen/pointer_fill_style_circle_diameter"
|
android:layout_width="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:layout_height="@dimen/pointer_fill_style_circle_diameter"
|
android:layout_height="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:maxWidth="@dimen/pointer_fill_style_circle_diameter"
|
android:maxWidth="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:contentDescription="@string/pointer_fill_style_blue_button"
|
android:contentDescription="@string/pointer_fill_style_blue_button"
|
||||||
android:scaleType="center"
|
android:scaleType="center"
|
||||||
android:background="@drawable/pointer_icon_fill_color_background"
|
android:src="@drawable/pointer_icon_fill_color_background" />
|
||||||
android:src="@drawable/pointer_icon_fill_color_foreground" />
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@@ -153,19 +147,18 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:layout_weight="3" />
|
android:layout_weight="1" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/button_purple"
|
android:id="@+id/button_purple"
|
||||||
android:layout_width="@dimen/pointer_fill_style_circle_diameter"
|
android:layout_width="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:layout_weight="0"
|
android:layout_weight="0"
|
||||||
android:layout_height="@dimen/pointer_fill_style_circle_diameter"
|
android:layout_height="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:adjustViewBounds="true"
|
android:adjustViewBounds="true"
|
||||||
android:maxWidth="@dimen/pointer_fill_style_circle_diameter"
|
android:maxWidth="@dimen/pointer_fill_style_circle_background_outer_diameter"
|
||||||
android:contentDescription="@string/pointer_fill_style_purple_button"
|
android:contentDescription="@string/pointer_fill_style_purple_button"
|
||||||
android:scaleType="center"
|
android:scaleType="center"
|
||||||
android:background="@drawable/pointer_icon_fill_color_background"
|
android:src="@drawable/pointer_icon_fill_color_background" />
|
||||||
android:src="@drawable/pointer_icon_fill_color_foreground" />
|
|
||||||
|
|
||||||
<View
|
<View
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@@ -173,7 +166,7 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:importantForAccessibility="no"
|
android:importantForAccessibility="no"
|
||||||
android:layout_weight="4" />
|
android:layout_weight="1" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
@@ -1,86 +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.
|
|
||||||
-->
|
|
||||||
<RelativeLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:id="@+id/suw_lift"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/sud_layout_icon"
|
|
||||||
style="@style/SudGlifIcon"
|
|
||||||
android:layout_marginStart="48dp"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_marginTop="68dp"
|
|
||||||
android:scaleType="fitStart"
|
|
||||||
android:src="@drawable/ic_lock" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/SudGlifHeaderTitle"
|
|
||||||
android:id="@+id/suc_layout_title"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="138dp"
|
|
||||||
android:layout_marginStart="40dp"
|
|
||||||
android:layout_marginEnd="24dp"/>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
style="@style/SudDescription.Glif"
|
|
||||||
android:id="@+id/sud_layout_subtitle"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="206dp"
|
|
||||||
android:layout_marginStart="40dp"
|
|
||||||
android:layout_marginEnd="24dp"/>
|
|
||||||
|
|
||||||
<com.airbnb.lottie.LottieAnimationView
|
|
||||||
android:id="@+id/illustration_lottie"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="200dp"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_marginTop="206dp"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginEnd="17dp"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:lottie_autoPlay="true"
|
|
||||||
app:lottie_loop="true"
|
|
||||||
app:lottie_speed=".85" />
|
|
||||||
|
|
||||||
<include layout="@layout/udfps_enroll_enrolling_v2_udfps_view"/>
|
|
||||||
|
|
||||||
<Button
|
|
||||||
style="@style/SudGlifButton.Secondary"
|
|
||||||
android:id="@+id/skip_btn"
|
|
||||||
android:text="@string/security_settings_fingerprint_enroll_enrolling_skip"
|
|
||||||
android:layout_alignParentBottom="true"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_marginBottom="26dp"
|
|
||||||
android:layout_marginStart="66dp"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"/>
|
|
||||||
|
|
||||||
</RelativeLayout>
|
|
||||||
@@ -1,36 +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.
|
|
||||||
-->
|
|
||||||
<com.android.settings.biometrics2.ui.widget.UdfpsEnrollView
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/udfps_animation_view"
|
|
||||||
android:layout_width="218.42dp"
|
|
||||||
android:layout_height="216dp"
|
|
||||||
android:layout_alignParentTop="true"
|
|
||||||
android:layout_centerHorizontal="true"
|
|
||||||
android:layout_marginTop="553dp">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/udfps_enroll_animation_fp_progress_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
|
|
||||||
<!-- Fingerprint -->
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/udfps_enroll_animation_fp_view"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
</com.android.settings.biometrics2.ui.widget.UdfpsEnrollView>
|
|
||||||
@@ -77,8 +77,8 @@
|
|||||||
<!-- Switch bar disabled state color-->
|
<!-- Switch bar disabled state color-->
|
||||||
<color name="switch_bar_state_disabled_color">#1FE3E3E3</color>
|
<color name="switch_bar_state_disabled_color">#1FE3E3E3</color>
|
||||||
|
|
||||||
<!-- Pointer fill color setting outline color-->
|
<!-- Pointer fill color setting, fill selector's background color on hover. -->
|
||||||
<color name="pointer_fill_outline_color">#FFFFFF</color>
|
<color name="pointer_fill_hovered_color">#3E373C</color>
|
||||||
|
|
||||||
<!-- Connected displays -->
|
<!-- Connected displays -->
|
||||||
<color name="display_topology_background_color">@color/settingslib_color_charcoal</color>
|
<color name="display_topology_background_color">@color/settingslib_color_charcoal</color>
|
||||||
|
|||||||
@@ -219,8 +219,8 @@
|
|||||||
<!-- Switch bar disabled state color-->
|
<!-- Switch bar disabled state color-->
|
||||||
<color name="switch_bar_state_disabled_color">#1F1F1F1F</color>
|
<color name="switch_bar_state_disabled_color">#1F1F1F1F</color>
|
||||||
|
|
||||||
<!-- Pointer fill color setting outline color-->
|
<!-- Pointer fill color setting, fill selector's background color on hover. -->
|
||||||
<color name="pointer_fill_outline_color">#000000</color>
|
<color name="pointer_fill_hovered_color">#1C201A1E</color>
|
||||||
|
|
||||||
<!-- Connected displays -->
|
<!-- Connected displays -->
|
||||||
<color name="display_topology_background_color">@color/settingslib_color_grey100</color>
|
<color name="display_topology_background_color">@color/settingslib_color_grey100</color>
|
||||||
|
|||||||
@@ -180,21 +180,28 @@
|
|||||||
<dimen name="keyboard_picker_text_size">16sp</dimen>
|
<dimen name="keyboard_picker_text_size">16sp</dimen>
|
||||||
|
|
||||||
<!-- Pointer -->
|
<!-- Pointer -->
|
||||||
<dimen name="pointer_fill_container_height">88dp</dimen>
|
<dimen name="pointer_fill_container_height">80dp</dimen>
|
||||||
<dimen name="pointer_fill_container_max_width">448dp</dimen>
|
<dimen name="pointer_fill_container_max_width">468dp</dimen>
|
||||||
<dimen name="pointer_fill_style_container_padding">32dp</dimen>
|
<dimen name="pointer_fill_style_container_padding">32dp</dimen>
|
||||||
<dimen name="pointer_fill_style_circle_diameter">56dp</dimen>
|
<dimen name="pointer_fill_style_target_width">64dp</dimen>
|
||||||
<dimen name="pointer_fill_style_circle_hover_selected_diameter">52dp</dimen>
|
<dimen name="pointer_fill_style_circle_diameter">39dp</dimen>
|
||||||
<dimen name="pointer_fill_style_circle_hover_diameter">56dp</dimen>
|
<dimen name="pointer_fill_style_circle_outline_diameter">39.5dp</dimen>
|
||||||
<dimen name="pointer_fill_style_circle_selected_diameter">50dp</dimen>
|
<dimen name="pointer_fill_style_circle_background_corner_radius">20dp</dimen>
|
||||||
<dimen name="pointer_fill_style_circle_inner_diameter">40dp</dimen>
|
<dimen name="pointer_fill_style_circle_background_corner_inner_radius">16dp</dimen>
|
||||||
<dimen name="pointer_fill_style_circle_offset">8dp</dimen>
|
<dimen name="pointer_fill_style_circle_background_outer_diameter">64dp</dimen>
|
||||||
|
<dimen name="pointer_fill_style_circle_background_outer_diameter_less_stroke">62dp</dimen>
|
||||||
|
<dimen name="pointer_fill_style_circle_background_outer_diameter_selected">52dp</dimen>
|
||||||
|
<dimen name="pointer_fill_style_circle_background_outline_offset">1dp</dimen>
|
||||||
|
<dimen name="pointer_fill_style_circle_offset">12.5dp</dimen>
|
||||||
|
<dimen name="pointer_fill_style_circle_offset_selected">13.25dp</dimen>
|
||||||
|
<dimen name="pointer_fill_style_circle_outline_offset">12.25dp</dimen>
|
||||||
|
<dimen name="pointer_fill_style_circle_outline_offset_selected">13dp</dimen>
|
||||||
|
<dimen name="pointer_fill_style_circle_background_offset">7dp</dimen>
|
||||||
|
<dimen name="pointer_fill_style_circle_outline_stroke">1dp</dimen>
|
||||||
|
<dimen name="pointer_fill_style_circle_background_selected_outline_stroke">2dp</dimen>
|
||||||
<dimen name="pointer_fill_style_circle_padding">16dp</dimen>
|
<dimen name="pointer_fill_style_circle_padding">16dp</dimen>
|
||||||
<dimen name="pointer_fill_style_circle_selected_offset">3dp</dimen>
|
<dimen name="pointer_fill_style_checkmark_selected_padding">16dp</dimen>
|
||||||
<dimen name="pointer_fill_style_checkmark_selected_padding">14dp</dimen>
|
<dimen name="pointer_fill_style_checkmark_size">24dp</dimen>
|
||||||
<dimen name="pointer_fill_style_checkmark_hovered_padding">17dp</dimen>
|
|
||||||
<dimen name="pointer_fill_style_shape_selected_stroke">2dp</dimen>
|
|
||||||
<dimen name="pointer_fill_style_shape_hovered_stroke">4dp</dimen>
|
|
||||||
<dimen name="pointer_stroke_style_padding">8dp</dimen>
|
<dimen name="pointer_stroke_style_padding">8dp</dimen>
|
||||||
<dimen name="pointer_stroke_style_text_padding">21dp</dimen>
|
<dimen name="pointer_stroke_style_text_padding">21dp</dimen>
|
||||||
<dimen name="pointer_scale_padding">8dp</dimen>
|
<dimen name="pointer_scale_padding">8dp</dimen>
|
||||||
|
|||||||
@@ -46,4 +46,7 @@
|
|||||||
<!-- For screen lock options button -->
|
<!-- For screen lock options button -->
|
||||||
<item type="id" name="screen_lock_options" />
|
<item type="id" name="screen_lock_options" />
|
||||||
|
|
||||||
|
<!-- For some widgets still use this ids under com.android.settings.R-->
|
||||||
|
<item type="id" name="sud_layout_icon" />
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -5415,8 +5415,10 @@
|
|||||||
<string name="accessibility_toggle_high_text_contrast_preference_title">High contrast text</string>
|
<string name="accessibility_toggle_high_text_contrast_preference_title">High contrast text</string>
|
||||||
<!-- Summary for the accessibility preference to high contrast text. [CHAR LIMIT=NONE] -->
|
<!-- Summary for the accessibility preference to high contrast text. [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_toggle_high_text_contrast_preference_summary">Change text color to black or white. Maximizes contrast with the background.</string>
|
<string name="accessibility_toggle_high_text_contrast_preference_summary">Change text color to black or white. Maximizes contrast with the background.</string>
|
||||||
<!-- Content for the notification to high contrast text. [CHAR LIMIT=NONE] -->
|
<!-- Title for the notification that high contrast text has been replaced. [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_notification_high_contrast_text_content">High contrast text has a new look and feel.</string>
|
<string name="accessibility_notification_high_contrast_text_title">High contrast text has been replaced</string>
|
||||||
|
<!-- Text content for the notification that high contrast text has been replaced. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="accessibility_notification_high_contrast_text_content">Try Maximize text contrast instead. Find it in Settings.</string>
|
||||||
<!-- Action for the notification to high contrast text. [CHAR LIMIT=35] -->
|
<!-- Action for the notification to high contrast text. [CHAR LIMIT=35] -->
|
||||||
<string name="accessibility_notification_high_contrast_text_action">Open Settings</string>
|
<string name="accessibility_notification_high_contrast_text_action">Open Settings</string>
|
||||||
<!-- Title for the accessibility preference to high contrast text. [CHAR LIMIT=35] -->
|
<!-- Title for the accessibility preference to high contrast text. [CHAR LIMIT=35] -->
|
||||||
@@ -5669,7 +5671,9 @@
|
|||||||
<!-- Title for accessibility hearing device page footer. [CHAR LIMIT=40] -->
|
<!-- Title for accessibility hearing device page footer. [CHAR LIMIT=40] -->
|
||||||
<string name="accessibility_hearing_device_about_title">About hearing devices</string>
|
<string name="accessibility_hearing_device_about_title">About hearing devices</string>
|
||||||
<!-- Description for text in accessibility hearing aids footer. [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=7451899224828040581] -->
|
<!-- Description for text in accessibility hearing aids footer. [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=7451899224828040581] -->
|
||||||
<string name="accessibility_hearing_device_footer_summary">To find other hearing devices that aren’t supported by ASHA or LE Audio, tap <b>Pair new device</b> > <b>See more devices</b></string>
|
<string name="accessibility_hearing_device_footer_summary"><![CDATA[To find other hearing devices that aren’t supported by ASHA or LE Audio, tap <b>Pair new device</b> > <b>See more devices</b>]]></string>
|
||||||
|
<!-- Content description for text in accessibility hearing aids footer to be announce. Replace '>' to 'then' compare to non tts version. [CHAR LIMIT=NONE BACKUP_MESSAGE_ID=7451899224828040581] -->
|
||||||
|
<string name="accessibility_hearing_device_footer_summary_tts">To find other hearing devices that aren’t supported by ASHA or LE Audio, tap <b>Pair new device</b> then <b>See more devices</b></string>
|
||||||
<!-- Title for the pair hearing device page. [CHAR LIMIT=25] -->
|
<!-- Title for the pair hearing device page. [CHAR LIMIT=25] -->
|
||||||
<string name="accessibility_hearing_device_pairing_page_title">Pair hearing device</string>
|
<string name="accessibility_hearing_device_pairing_page_title">Pair hearing device</string>
|
||||||
<!-- Subtitle for the pair hearing device page. [CHAR LIMIT=NONE] -->
|
<!-- Subtitle for the pair hearing device page. [CHAR LIMIT=NONE] -->
|
||||||
@@ -10663,6 +10667,11 @@
|
|||||||
<string name="admin_financed_message">Your device administrator may be able to access data
|
<string name="admin_financed_message">Your device administrator may be able to access data
|
||||||
associated with this device, manage apps, and change this device\’s settings.</string>
|
associated with this device, manage apps, and change this device\’s settings.</string>
|
||||||
|
|
||||||
|
<!-- Title for dialog displayed when user taps a setting on their phone that's blocked by Advanced Protection. [CHAR LIMIT=50] -->
|
||||||
|
<string name="disabled_by_advanced_protection_title">Prevented by Advanced Protection</string>
|
||||||
|
<!-- Short summary for dialog displayed when user taps a setting on their phone that's blocked by Advanced Protection. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="disabled_by_advanced_protection_message">This action is not allowed because Advanced Protection is on for your device.</string>
|
||||||
|
|
||||||
<!-- Turn off a conditional state of the device (e.g. airplane mode, or hotspot) [CHAR LIMIT=30] -->
|
<!-- Turn off a conditional state of the device (e.g. airplane mode, or hotspot) [CHAR LIMIT=30] -->
|
||||||
<string name="condition_turn_off">Turn off</string>
|
<string name="condition_turn_off">Turn off</string>
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,8 @@
|
|||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:key="toggle_high_text_contrast_preference"
|
android:key="toggle_high_text_contrast_preference"
|
||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
android:summary="@string/accessibility_toggle_high_text_contrast_preference_summary"
|
android:title="@string/accessibility_toggle_maximize_text_contrast_preference_title"
|
||||||
android:title="@string/accessibility_toggle_high_text_contrast_preference_title"
|
android:summary="@string/accessibility_toggle_maximize_text_contrast_preference_summary"
|
||||||
settings:controller=
|
settings:controller=
|
||||||
"com.android.settings.accessibility.HighTextContrastPreferenceController" />
|
"com.android.settings.accessibility.HighTextContrastPreferenceController" />
|
||||||
|
|
||||||
|
|||||||
@@ -65,7 +65,6 @@
|
|||||||
|
|
||||||
<com.android.settings.accessibility.AccessibilityFooterPreference
|
<com.android.settings.accessibility.AccessibilityFooterPreference
|
||||||
android:key="hearing_device_footer"
|
android:key="hearing_device_footer"
|
||||||
android:title="@string/accessibility_hearing_device_footer_summary"
|
|
||||||
android:selectable="false"
|
android:selectable="false"
|
||||||
settings:searchable="false"
|
settings:searchable="false"
|
||||||
settings:controller="com.android.settings.accessibility.HearingDeviceFooterPreferenceController"/>
|
settings:controller="com.android.settings.accessibility.HearingDeviceFooterPreferenceController"/>
|
||||||
|
|||||||
@@ -56,8 +56,8 @@
|
|||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:key="toggle_high_text_contrast_preference"
|
android:key="toggle_high_text_contrast_preference"
|
||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
android:summary="@string/accessibility_toggle_high_text_contrast_preference_summary"
|
android:title="@string/accessibility_toggle_maximize_text_contrast_preference_title"
|
||||||
android:title="@string/accessibility_toggle_high_text_contrast_preference_title" />
|
android:summary="@string/accessibility_toggle_maximize_text_contrast_preference_summary" />
|
||||||
|
|
||||||
<com.android.settings.accessibility.TextReadingResetPreference
|
<com.android.settings.accessibility.TextReadingResetPreference
|
||||||
android:key="reset"
|
android:key="reset"
|
||||||
|
|||||||
@@ -17,6 +17,10 @@
|
|||||||
package com.android.settings.accessibility;
|
package com.android.settings.accessibility;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.text.Html;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
|
||||||
@@ -32,4 +36,24 @@ public class HearingDeviceFooterPreferenceController extends
|
|||||||
protected String getIntroductionTitle() {
|
protected String getIntroductionTitle() {
|
||||||
return mContext.getString(R.string.accessibility_hearing_device_about_title);
|
return mContext.getString(R.string.accessibility_hearing_device_about_title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(@NonNull PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
|
||||||
|
final AccessibilityFooterPreference footerPreference =
|
||||||
|
screen.findPreference(getPreferenceKey());
|
||||||
|
// We use html tag inside footer string, so it is better to load from html to have better
|
||||||
|
// html tag support.
|
||||||
|
final CharSequence title = Html.fromHtml(
|
||||||
|
mContext.getString(R.string.accessibility_hearing_device_footer_summary),
|
||||||
|
Html.FROM_HTML_MODE_COMPACT, /* imageGetter= */ null, /* tagHandler= */ null);
|
||||||
|
footerPreference.setTitle(title);
|
||||||
|
|
||||||
|
// Need to update contentDescription string to announce "than" rather than ">"
|
||||||
|
final String summaryTts = mContext.getString(
|
||||||
|
R.string.accessibility_hearing_device_footer_summary_tts);
|
||||||
|
final String contentDescription = getIntroductionTitle() + "\n\n" + summaryTts;
|
||||||
|
footerPreference.setContentDescription(contentDescription);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
public class HighContrastTextMigrationReceiver extends BroadcastReceiver {
|
public class HighContrastTextMigrationReceiver extends BroadcastReceiver {
|
||||||
private static final String TAG = HighContrastTextMigrationReceiver.class.getSimpleName();
|
private static final String TAG = HighContrastTextMigrationReceiver.class.getSimpleName();
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String NOTIFICATION_CHANNEL = "high_contrast_text_notification_channel";
|
static final String NOTIFICATION_CHANNEL = "accessibility_notification_channel";
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final String ACTION_RESTORED =
|
static final String ACTION_RESTORED =
|
||||||
"com.android.settings.accessibility.ACTION_HIGH_CONTRAST_TEXT_RESTORED";
|
"com.android.settings.accessibility.ACTION_HIGH_CONTRAST_TEXT_RESTORED";
|
||||||
@@ -120,7 +120,7 @@ public class HighContrastTextMigrationReceiver extends BroadcastReceiver {
|
|||||||
NOTIFICATION_CHANNEL)
|
NOTIFICATION_CHANNEL)
|
||||||
.setSmallIcon(R.drawable.ic_settings_24dp)
|
.setSmallIcon(R.drawable.ic_settings_24dp)
|
||||||
.setContentTitle(context.getString(
|
.setContentTitle(context.getString(
|
||||||
R.string.accessibility_toggle_high_text_contrast_preference_title))
|
R.string.accessibility_notification_high_contrast_text_title))
|
||||||
.setContentText(context.getString(
|
.setContentText(context.getString(
|
||||||
R.string.accessibility_notification_high_contrast_text_content))
|
R.string.accessibility_notification_high_contrast_text_content))
|
||||||
.setAutoCancel(true);
|
.setAutoCancel(true);
|
||||||
@@ -149,8 +149,7 @@ public class HighContrastTextMigrationReceiver extends BroadcastReceiver {
|
|||||||
context.getSystemService(NotificationManager.class);
|
context.getSystemService(NotificationManager.class);
|
||||||
NotificationChannel notificationChannel = new NotificationChannel(
|
NotificationChannel notificationChannel = new NotificationChannel(
|
||||||
NOTIFICATION_CHANNEL,
|
NOTIFICATION_CHANNEL,
|
||||||
context.getString(
|
context.getString(R.string.accessibility_settings),
|
||||||
R.string.accessibility_toggle_high_text_contrast_preference_title),
|
|
||||||
NotificationManager.IMPORTANCE_LOW);
|
NotificationManager.IMPORTANCE_LOW);
|
||||||
notificationManager.createNotificationChannel(notificationChannel);
|
notificationManager.createNotificationChannel(notificationChannel);
|
||||||
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
|
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
|
||||||
|
|||||||
@@ -21,25 +21,29 @@ import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO;
|
|||||||
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
|
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES;
|
||||||
import static android.view.View.VISIBLE;
|
import static android.view.View.VISIBLE;
|
||||||
|
|
||||||
|
import static com.android.settings.bluetooth.BluetoothDetailsAmbientVolumePreferenceController.KEY_AMBIENT_VOLUME_SLIDER;
|
||||||
import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_LEFT;
|
import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_LEFT;
|
||||||
import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_RIGHT;
|
import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_RIGHT;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.ArrayMap;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.preference.PreferenceGroup;
|
import androidx.preference.PreferenceGroup;
|
||||||
import androidx.preference.PreferenceViewHolder;
|
import androidx.preference.PreferenceViewHolder;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.widget.SeekBarPreference;
|
import com.android.settings.widget.SeekBarPreference;
|
||||||
|
import com.android.settingslib.bluetooth.AmbientVolumeUi;
|
||||||
|
|
||||||
|
import com.google.common.collect.BiMap;
|
||||||
|
import com.google.common.collect.HashBiMap;
|
||||||
import com.google.common.primitives.Ints;
|
import com.google.common.primitives.Ints;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,27 +53,13 @@ import java.util.Map;
|
|||||||
* separated control for devices in the same set. Toggle the expand icon will make the UI switch
|
* separated control for devices in the same set. Toggle the expand icon will make the UI switch
|
||||||
* between unified and separated control.
|
* between unified and separated control.
|
||||||
*/
|
*/
|
||||||
public class AmbientVolumePreference extends PreferenceGroup {
|
public class AmbientVolumePreference extends PreferenceGroup implements AmbientVolumeUi {
|
||||||
|
|
||||||
/** Interface definition for a callback to be invoked when the icon is clicked. */
|
private static final int ORDER_AMBIENT_VOLUME_CONTROL_UNIFIED = 0;
|
||||||
public interface OnIconClickListener {
|
private static final int ORDER_AMBIENT_VOLUME_CONTROL_SEPARATED = 1;
|
||||||
/** Called when the expand icon is clicked. */
|
|
||||||
void onExpandIconClick();
|
|
||||||
|
|
||||||
/** Called when the ambient volume icon is clicked. */
|
|
||||||
void onAmbientVolumeIconClick();
|
|
||||||
};
|
|
||||||
|
|
||||||
static final float ROTATION_COLLAPSED = 0f;
|
|
||||||
static final float ROTATION_EXPANDED = 180f;
|
|
||||||
static final int AMBIENT_VOLUME_LEVEL_MIN = 0;
|
|
||||||
static final int AMBIENT_VOLUME_LEVEL_MAX = 24;
|
|
||||||
static final int AMBIENT_VOLUME_LEVEL_DEFAULT = 24;
|
|
||||||
static final int SIDE_UNIFIED = 999;
|
|
||||||
static final List<Integer> VALID_SIDES = List.of(SIDE_UNIFIED, SIDE_LEFT, SIDE_RIGHT);
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private OnIconClickListener mListener;
|
private AmbientVolumeUiListener mListener;
|
||||||
@Nullable
|
@Nullable
|
||||||
private View mExpandIcon;
|
private View mExpandIcon;
|
||||||
@Nullable
|
@Nullable
|
||||||
@@ -78,27 +68,21 @@ public class AmbientVolumePreference extends PreferenceGroup {
|
|||||||
private boolean mExpanded = false;
|
private boolean mExpanded = false;
|
||||||
private boolean mMutable = false;
|
private boolean mMutable = false;
|
||||||
private boolean mMuted = false;
|
private boolean mMuted = false;
|
||||||
private Map<Integer, SeekBarPreference> mSideToSliderMap = new ArrayMap<>();
|
private final BiMap<Integer, SeekBarPreference> mSideToSliderMap = HashBiMap.create();
|
||||||
|
|
||||||
/**
|
|
||||||
* Ambient volume level for hearing device ambient control icon
|
|
||||||
* <p>
|
|
||||||
* This icon visually represents the current ambient gain setting.
|
|
||||||
* It displays separate levels for the left and right sides, each with 5 levels ranging from 0
|
|
||||||
* to 4.
|
|
||||||
* <p>
|
|
||||||
* To represent the combined left/right levels with a single value, the following calculation
|
|
||||||
* is used:
|
|
||||||
* finalLevel = (leftLevel * 5) + rightLevel
|
|
||||||
* For example:
|
|
||||||
* <ul>
|
|
||||||
* <li>If left level is 2 and right level is 3, the final level will be 13 (2 * 5 + 3)</li>
|
|
||||||
* <li>If both left and right levels are 0, the final level will be 0</li>
|
|
||||||
* <li>If both left and right levels are 4, the final level will be 24</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
private int mVolumeLevel = AMBIENT_VOLUME_LEVEL_DEFAULT;
|
private int mVolumeLevel = AMBIENT_VOLUME_LEVEL_DEFAULT;
|
||||||
|
|
||||||
|
private final OnPreferenceChangeListener mPreferenceChangeListener =
|
||||||
|
(slider, v) -> {
|
||||||
|
if (slider instanceof SeekBarPreference && v instanceof final Integer value) {
|
||||||
|
final Integer side = mSideToSliderMap.inverse().get(slider);
|
||||||
|
if (mListener != null && side != null) {
|
||||||
|
mListener.onSliderValueChange(side, value);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
public AmbientVolumePreference(@NonNull Context context) {
|
public AmbientVolumePreference(@NonNull Context context) {
|
||||||
super(context, null);
|
super(context, null);
|
||||||
setLayoutResource(R.layout.preference_ambient_volume);
|
setLayoutResource(R.layout.preference_ambient_volume);
|
||||||
@@ -138,7 +122,8 @@ public class AmbientVolumePreference extends PreferenceGroup {
|
|||||||
updateExpandIcon();
|
updateExpandIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setExpandable(boolean expandable) {
|
@Override
|
||||||
|
public void setExpandable(boolean expandable) {
|
||||||
mExpandable = expandable;
|
mExpandable = expandable;
|
||||||
if (!mExpandable) {
|
if (!mExpandable) {
|
||||||
setExpanded(false);
|
setExpanded(false);
|
||||||
@@ -146,11 +131,13 @@ public class AmbientVolumePreference extends PreferenceGroup {
|
|||||||
updateExpandIcon();
|
updateExpandIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isExpandable() {
|
@Override
|
||||||
|
public boolean isExpandable() {
|
||||||
return mExpandable;
|
return mExpandable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setExpanded(boolean expanded) {
|
@Override
|
||||||
|
public void setExpanded(boolean expanded) {
|
||||||
if (!mExpandable && expanded) {
|
if (!mExpandable && expanded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -159,11 +146,13 @@ public class AmbientVolumePreference extends PreferenceGroup {
|
|||||||
updateLayout();
|
updateLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isExpanded() {
|
@Override
|
||||||
|
public boolean isExpanded() {
|
||||||
return mExpanded;
|
return mExpanded;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMutable(boolean mutable) {
|
@Override
|
||||||
|
public void setMutable(boolean mutable) {
|
||||||
mMutable = mutable;
|
mMutable = mutable;
|
||||||
if (!mMutable) {
|
if (!mMutable) {
|
||||||
mVolumeLevel = AMBIENT_VOLUME_LEVEL_DEFAULT;
|
mVolumeLevel = AMBIENT_VOLUME_LEVEL_DEFAULT;
|
||||||
@@ -172,11 +161,13 @@ public class AmbientVolumePreference extends PreferenceGroup {
|
|||||||
updateVolumeIcon();
|
updateVolumeIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isMutable() {
|
@Override
|
||||||
|
public boolean isMutable() {
|
||||||
return mMutable;
|
return mMutable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMuted(boolean muted) {
|
@Override
|
||||||
|
public void setMuted(boolean muted) {
|
||||||
if (!mMutable && muted) {
|
if (!mMutable && muted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -189,25 +180,35 @@ public class AmbientVolumePreference extends PreferenceGroup {
|
|||||||
updateVolumeIcon();
|
updateVolumeIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isMuted() {
|
@Override
|
||||||
|
public boolean isMuted() {
|
||||||
return mMuted;
|
return mMuted;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setOnIconClickListener(@Nullable OnIconClickListener listener) {
|
@Override
|
||||||
|
public void setListener(@Nullable AmbientVolumeUiListener listener) {
|
||||||
mListener = listener;
|
mListener = listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSliders(Map<Integer, SeekBarPreference> sideToSliderMap) {
|
@Override
|
||||||
mSideToSliderMap = sideToSliderMap;
|
public void setupSliders(@NonNull Map<Integer, BluetoothDevice> sideToDeviceMap) {
|
||||||
for (SeekBarPreference preference : sideToSliderMap.values()) {
|
sideToDeviceMap.forEach((side, device) ->
|
||||||
if (findPreference(preference.getKey()) == null) {
|
createSlider(side, ORDER_AMBIENT_VOLUME_CONTROL_SEPARATED + side));
|
||||||
addPreference(preference);
|
createSlider(SIDE_UNIFIED, ORDER_AMBIENT_VOLUME_CONTROL_UNIFIED);
|
||||||
|
|
||||||
|
if (!mSideToSliderMap.isEmpty()) {
|
||||||
|
for (int side : VALID_SIDES) {
|
||||||
|
final SeekBarPreference slider = mSideToSliderMap.get(side);
|
||||||
|
if (slider != null && findPreference(slider.getKey()) == null) {
|
||||||
|
addPreference(slider);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateLayout();
|
updateLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSliderEnabled(int side, boolean enabled) {
|
@Override
|
||||||
|
public void setSliderEnabled(int side, boolean enabled) {
|
||||||
SeekBarPreference slider = mSideToSliderMap.get(side);
|
SeekBarPreference slider = mSideToSliderMap.get(side);
|
||||||
if (slider != null && slider.isEnabled() != enabled) {
|
if (slider != null && slider.isEnabled() != enabled) {
|
||||||
slider.setEnabled(enabled);
|
slider.setEnabled(enabled);
|
||||||
@@ -215,7 +216,8 @@ public class AmbientVolumePreference extends PreferenceGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSliderValue(int side, int value) {
|
@Override
|
||||||
|
public void setSliderValue(int side, int value) {
|
||||||
SeekBarPreference slider = mSideToSliderMap.get(side);
|
SeekBarPreference slider = mSideToSliderMap.get(side);
|
||||||
if (slider != null && slider.getProgress() != value) {
|
if (slider != null && slider.getProgress() != value) {
|
||||||
slider.setProgress(value);
|
slider.setProgress(value);
|
||||||
@@ -223,7 +225,8 @@ public class AmbientVolumePreference extends PreferenceGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setSliderRange(int side, int min, int max) {
|
@Override
|
||||||
|
public void setSliderRange(int side, int min, int max) {
|
||||||
SeekBarPreference slider = mSideToSliderMap.get(side);
|
SeekBarPreference slider = mSideToSliderMap.get(side);
|
||||||
if (slider != null) {
|
if (slider != null) {
|
||||||
slider.setMin(min);
|
slider.setMin(min);
|
||||||
@@ -231,7 +234,8 @@ public class AmbientVolumePreference extends PreferenceGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateLayout() {
|
@Override
|
||||||
|
public void updateLayout() {
|
||||||
mSideToSliderMap.forEach((side, slider) -> {
|
mSideToSliderMap.forEach((side, slider) -> {
|
||||||
if (side == SIDE_UNIFIED) {
|
if (side == SIDE_UNIFIED) {
|
||||||
slider.setVisible(!mExpanded);
|
slider.setVisible(!mExpanded);
|
||||||
@@ -279,8 +283,7 @@ public class AmbientVolumePreference extends PreferenceGroup {
|
|||||||
mExpandIcon.setVisibility(mExpandable ? VISIBLE : GONE);
|
mExpandIcon.setVisibility(mExpandable ? VISIBLE : GONE);
|
||||||
mExpandIcon.setRotation(mExpanded ? ROTATION_EXPANDED : ROTATION_COLLAPSED);
|
mExpandIcon.setRotation(mExpanded ? ROTATION_EXPANDED : ROTATION_COLLAPSED);
|
||||||
if (mExpandable) {
|
if (mExpandable) {
|
||||||
final int stringRes = mExpanded
|
final int stringRes = mExpanded ? R.string.bluetooth_ambient_volume_control_collapse
|
||||||
? R.string.bluetooth_ambient_volume_control_collapse
|
|
||||||
: R.string.bluetooth_ambient_volume_control_expand;
|
: R.string.bluetooth_ambient_volume_control_expand;
|
||||||
mExpandIcon.setContentDescription(getContext().getString(stringRes));
|
mExpandIcon.setContentDescription(getContext().getString(stringRes));
|
||||||
} else {
|
} else {
|
||||||
@@ -294,8 +297,7 @@ public class AmbientVolumePreference extends PreferenceGroup {
|
|||||||
}
|
}
|
||||||
mVolumeIcon.setImageLevel(mMuted ? 0 : mVolumeLevel);
|
mVolumeIcon.setImageLevel(mMuted ? 0 : mVolumeLevel);
|
||||||
if (mMutable) {
|
if (mMutable) {
|
||||||
final int stringRes = mMuted
|
final int stringRes = mMuted ? R.string.bluetooth_ambient_volume_unmute
|
||||||
? R.string.bluetooth_ambient_volume_unmute
|
|
||||||
: R.string.bluetooth_ambient_volume_mute;
|
: R.string.bluetooth_ambient_volume_mute;
|
||||||
mVolumeIcon.setContentDescription(getContext().getString(stringRes));
|
mVolumeIcon.setContentDescription(getContext().getString(stringRes));
|
||||||
mVolumeIcon.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
|
mVolumeIcon.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
|
||||||
@@ -304,4 +306,27 @@ public class AmbientVolumePreference extends PreferenceGroup {
|
|||||||
mVolumeIcon.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
|
mVolumeIcon.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createSlider(int side, int order) {
|
||||||
|
if (mSideToSliderMap.containsKey(side)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SeekBarPreference slider = new SeekBarPreference(getContext());
|
||||||
|
slider.setKey(KEY_AMBIENT_VOLUME_SLIDER + "_" + side);
|
||||||
|
slider.setOrder(order);
|
||||||
|
slider.setOnPreferenceChangeListener(mPreferenceChangeListener);
|
||||||
|
if (side == SIDE_LEFT) {
|
||||||
|
slider.setTitle(
|
||||||
|
getContext().getString(R.string.bluetooth_ambient_volume_control_left));
|
||||||
|
} else if (side == SIDE_RIGHT) {
|
||||||
|
slider.setTitle(
|
||||||
|
getContext().getString(R.string.bluetooth_ambient_volume_control_right));
|
||||||
|
}
|
||||||
|
mSideToSliderMap.put(side, slider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
Map<Integer, SeekBarPreference> getSliders() {
|
||||||
|
return mSideToSliderMap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,41 +16,20 @@
|
|||||||
|
|
||||||
package com.android.settings.bluetooth;
|
package com.android.settings.bluetooth;
|
||||||
|
|
||||||
import static android.bluetooth.AudioInputControl.MUTE_NOT_MUTED;
|
|
||||||
import static android.bluetooth.AudioInputControl.MUTE_MUTED;
|
|
||||||
import static android.bluetooth.BluetoothDevice.BOND_BONDED;
|
|
||||||
|
|
||||||
import static com.android.settings.bluetooth.AmbientVolumePreference.SIDE_UNIFIED;
|
|
||||||
import static com.android.settings.bluetooth.AmbientVolumePreference.VALID_SIDES;
|
|
||||||
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.KEY_HEARING_DEVICE_GROUP;
|
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.KEY_HEARING_DEVICE_GROUP;
|
||||||
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.ORDER_AMBIENT_VOLUME;
|
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.ORDER_AMBIENT_VOLUME;
|
||||||
import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_INVALID;
|
|
||||||
import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_LEFT;
|
|
||||||
import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_RIGHT;
|
|
||||||
import static com.android.settingslib.bluetooth.HearingDeviceLocalDataManager.Data.INVALID_VOLUME;
|
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
|
||||||
import android.bluetooth.BluetoothProfile;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.ArraySet;
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.preference.Preference;
|
|
||||||
import androidx.preference.PreferenceCategory;
|
import androidx.preference.PreferenceCategory;
|
||||||
import androidx.preference.PreferenceFragmentCompat;
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settingslib.bluetooth.AmbientVolumeUiController;
|
||||||
import com.android.settings.widget.SeekBarPreference;
|
|
||||||
import com.android.settingslib.bluetooth.AmbientVolumeController;
|
|
||||||
import com.android.settingslib.bluetooth.BluetoothCallback;
|
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
import com.android.settingslib.bluetooth.HearingDeviceLocalDataManager;
|
|
||||||
import com.android.settingslib.bluetooth.HearingDeviceLocalDataManager.Data;
|
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
@@ -58,39 +37,21 @@ import com.android.settingslib.core.lifecycle.events.OnStart;
|
|||||||
import com.android.settingslib.core.lifecycle.events.OnStop;
|
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||||
import com.android.settingslib.utils.ThreadUtils;
|
import com.android.settingslib.utils.ThreadUtils;
|
||||||
|
|
||||||
import com.google.common.collect.BiMap;
|
/** A {@link BluetoothDetailsController} that manages ambient volume preference. */
|
||||||
import com.google.common.collect.HashBiMap;
|
public class BluetoothDetailsAmbientVolumePreferenceController extends BluetoothDetailsController
|
||||||
|
implements OnStart, OnStop {
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/** A {@link BluetoothDetailsController} that manages ambient volume control preferences. */
|
|
||||||
public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|
||||||
BluetoothDetailsController implements Preference.OnPreferenceChangeListener,
|
|
||||||
HearingDeviceLocalDataManager.OnDeviceLocalDataChangeListener, OnStart, OnStop,
|
|
||||||
AmbientVolumeController.AmbientVolumeControlCallback, BluetoothCallback {
|
|
||||||
|
|
||||||
private static final boolean DEBUG = true;
|
private static final boolean DEBUG = true;
|
||||||
private static final String TAG = "AmbientPrefController";
|
private static final String TAG = "AmbientPrefController";
|
||||||
|
|
||||||
static final String KEY_AMBIENT_VOLUME = "ambient_volume";
|
static final String KEY_AMBIENT_VOLUME = "ambient_volume";
|
||||||
static final String KEY_AMBIENT_VOLUME_SLIDER = "ambient_volume_slider";
|
static final String KEY_AMBIENT_VOLUME_SLIDER = "ambient_volume_slider";
|
||||||
private static final int ORDER_AMBIENT_VOLUME_CONTROL_UNIFIED = 0;
|
|
||||||
private static final int ORDER_AMBIENT_VOLUME_CONTROL_SEPARATED = 1;
|
|
||||||
|
|
||||||
private final LocalBluetoothManager mBluetoothManager;
|
private final LocalBluetoothManager mBluetoothManager;
|
||||||
private final Set<CachedBluetoothDevice> mCachedDevices = new ArraySet<>();
|
|
||||||
private final BiMap<Integer, BluetoothDevice> mSideToDeviceMap = HashBiMap.create();
|
|
||||||
private final BiMap<Integer, SeekBarPreference> mSideToSliderMap = HashBiMap.create();
|
|
||||||
private final HearingDeviceLocalDataManager mLocalDataManager;
|
|
||||||
private final AmbientVolumeController mVolumeController;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private PreferenceCategory mDeviceControls;
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private AmbientVolumePreference mPreference;
|
private AmbientVolumePreference mPreference;
|
||||||
@Nullable
|
@Nullable
|
||||||
private Toast mToast;
|
private AmbientVolumeUiController mAmbientUiController;
|
||||||
|
|
||||||
public BluetoothDetailsAmbientVolumePreferenceController(@NonNull Context context,
|
public BluetoothDetailsAmbientVolumePreferenceController(@NonNull Context context,
|
||||||
@NonNull LocalBluetoothManager manager,
|
@NonNull LocalBluetoothManager manager,
|
||||||
@@ -99,45 +60,42 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
@NonNull Lifecycle lifecycle) {
|
@NonNull Lifecycle lifecycle) {
|
||||||
super(context, fragment, device, lifecycle);
|
super(context, fragment, device, lifecycle);
|
||||||
mBluetoothManager = manager;
|
mBluetoothManager = manager;
|
||||||
mLocalDataManager = new HearingDeviceLocalDataManager(context);
|
|
||||||
mLocalDataManager.setOnDeviceLocalDataChangeListener(this,
|
|
||||||
ThreadUtils.getBackgroundExecutor());
|
|
||||||
mVolumeController = new AmbientVolumeController(manager.getProfileManager(), this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
BluetoothDetailsAmbientVolumePreferenceController(@NonNull Context context,
|
public BluetoothDetailsAmbientVolumePreferenceController(@NonNull Context context,
|
||||||
@NonNull LocalBluetoothManager manager,
|
@NonNull LocalBluetoothManager manager,
|
||||||
@NonNull PreferenceFragmentCompat fragment,
|
@NonNull PreferenceFragmentCompat fragment,
|
||||||
@NonNull CachedBluetoothDevice device,
|
@NonNull CachedBluetoothDevice device,
|
||||||
@NonNull Lifecycle lifecycle,
|
@NonNull Lifecycle lifecycle,
|
||||||
@NonNull HearingDeviceLocalDataManager localSettings,
|
@NonNull AmbientVolumeUiController uiController) {
|
||||||
@NonNull AmbientVolumeController volumeController) {
|
|
||||||
super(context, fragment, device, lifecycle);
|
super(context, fragment, device, lifecycle);
|
||||||
mBluetoothManager = manager;
|
mBluetoothManager = manager;
|
||||||
mLocalDataManager = localSettings;
|
mAmbientUiController = uiController;
|
||||||
mVolumeController = volumeController;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init(PreferenceScreen screen) {
|
protected void init(PreferenceScreen screen) {
|
||||||
mDeviceControls = screen.findPreference(KEY_HEARING_DEVICE_GROUP);
|
PreferenceCategory deviceControls = screen.findPreference(KEY_HEARING_DEVICE_GROUP);
|
||||||
if (mDeviceControls == null) {
|
if (deviceControls == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loadDevices();
|
mPreference = new AmbientVolumePreference(deviceControls.getContext());
|
||||||
|
mPreference.setKey(KEY_AMBIENT_VOLUME);
|
||||||
|
mPreference.setOrder(ORDER_AMBIENT_VOLUME);
|
||||||
|
deviceControls.addPreference(mPreference);
|
||||||
|
|
||||||
|
mAmbientUiController = new AmbientVolumeUiController(mContext, mBluetoothManager,
|
||||||
|
mPreference);
|
||||||
|
mAmbientUiController.loadDevice(mCachedDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
ThreadUtils.postOnBackgroundThread(() -> {
|
ThreadUtils.postOnBackgroundThread(() -> {
|
||||||
mBluetoothManager.getEventManager().registerCallback(this);
|
if (mAmbientUiController != null) {
|
||||||
mLocalDataManager.start();
|
mAmbientUiController.start();
|
||||||
mCachedDevices.forEach(device -> {
|
}
|
||||||
device.registerCallback(ThreadUtils.getBackgroundExecutor(), this);
|
|
||||||
mVolumeController.registerCallback(ThreadUtils.getBackgroundExecutor(),
|
|
||||||
device.getDevice());
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,12 +111,9 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
ThreadUtils.postOnBackgroundThread(() -> {
|
ThreadUtils.postOnBackgroundThread(() -> {
|
||||||
mBluetoothManager.getEventManager().unregisterCallback(this);
|
if (mAmbientUiController != null) {
|
||||||
mLocalDataManager.stop();
|
mAmbientUiController.stop();
|
||||||
mCachedDevices.forEach(device -> {
|
}
|
||||||
device.unregisterCallback(this);
|
|
||||||
mVolumeController.unregisterCallback(device.getDevice());
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,16 +122,8 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
if (!isAvailable()) {
|
if (!isAvailable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean shouldShowAmbientControl = isAmbientControlAvailable();
|
if (mAmbientUiController != null) {
|
||||||
if (shouldShowAmbientControl) {
|
mAmbientUiController.refresh();
|
||||||
if (mPreference != null) {
|
|
||||||
mPreference.setVisible(true);
|
|
||||||
}
|
|
||||||
loadRemoteDataToUi();
|
|
||||||
} else {
|
|
||||||
if (mPreference != null) {
|
|
||||||
mPreference.setVisible(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,424 +138,4 @@ public class BluetoothDetailsAmbientVolumePreferenceController extends
|
|||||||
public String getPreferenceKey() {
|
public String getPreferenceKey() {
|
||||||
return KEY_AMBIENT_VOLUME;
|
return KEY_AMBIENT_VOLUME;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onPreferenceChange(@NonNull Preference preference, @Nullable Object newValue) {
|
|
||||||
if (preference instanceof SeekBarPreference && newValue instanceof final Integer value) {
|
|
||||||
final int side = mSideToSliderMap.inverse().getOrDefault(preference, SIDE_INVALID);
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "onPreferenceChange: side=" + side + ", value=" + value);
|
|
||||||
}
|
|
||||||
setVolumeIfValid(side, value);
|
|
||||||
|
|
||||||
Runnable setAmbientRunnable = () -> {
|
|
||||||
if (side == SIDE_UNIFIED) {
|
|
||||||
mSideToDeviceMap.forEach((s, d) -> mVolumeController.setAmbient(d, value));
|
|
||||||
} else {
|
|
||||||
final BluetoothDevice device = mSideToDeviceMap.get(side);
|
|
||||||
mVolumeController.setAmbient(device, value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isControlMuted()) {
|
|
||||||
// User drag on the volume slider when muted. Unmute the devices first.
|
|
||||||
if (mPreference != null) {
|
|
||||||
mPreference.setMuted(false);
|
|
||||||
}
|
|
||||||
for (BluetoothDevice device : mSideToDeviceMap.values()) {
|
|
||||||
mVolumeController.setMuted(device, false);
|
|
||||||
}
|
|
||||||
// Restore the value before muted
|
|
||||||
loadLocalDataToUi();
|
|
||||||
// Delay set ambient on remote device since the immediately sequential command
|
|
||||||
// might get failed sometimes
|
|
||||||
mContext.getMainThreadHandler().postDelayed(setAmbientRunnable, 1000L);
|
|
||||||
} else {
|
|
||||||
setAmbientRunnable.run();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onProfileConnectionStateChanged(@NonNull CachedBluetoothDevice cachedDevice,
|
|
||||||
int state, int bluetoothProfile) {
|
|
||||||
if (bluetoothProfile == BluetoothProfile.VOLUME_CONTROL
|
|
||||||
&& state == BluetoothProfile.STATE_CONNECTED
|
|
||||||
&& mCachedDevices.contains(cachedDevice)) {
|
|
||||||
// After VCP connected, AICS may not ready yet and still return invalid value, delay
|
|
||||||
// a while to wait AICS ready as a workaround
|
|
||||||
mContext.getMainThreadHandler().postDelayed(this::refresh, 1000L);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDeviceAttributesChanged() {
|
|
||||||
mCachedDevices.forEach(device -> {
|
|
||||||
device.unregisterCallback(this);
|
|
||||||
mVolumeController.unregisterCallback(device.getDevice());
|
|
||||||
});
|
|
||||||
mContext.getMainExecutor().execute(() -> {
|
|
||||||
loadDevices();
|
|
||||||
if (!mCachedDevices.isEmpty()) {
|
|
||||||
refresh();
|
|
||||||
}
|
|
||||||
ThreadUtils.postOnBackgroundThread(() ->
|
|
||||||
mCachedDevices.forEach(device -> {
|
|
||||||
device.registerCallback(ThreadUtils.getBackgroundExecutor(), this);
|
|
||||||
mVolumeController.registerCallback(ThreadUtils.getBackgroundExecutor(),
|
|
||||||
device.getDevice());
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDeviceLocalDataChange(@NonNull String address, @Nullable Data data) {
|
|
||||||
if (data == null) {
|
|
||||||
// The local data is removed because the device is unpaired, do nothing
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (BluetoothDevice device : mSideToDeviceMap.values()) {
|
|
||||||
if (device.getAnonymizedAddress().equals(address)) {
|
|
||||||
mContext.getMainExecutor().execute(() -> loadLocalDataToUi(device));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onVolumeControlServiceConnected() {
|
|
||||||
mCachedDevices.forEach(
|
|
||||||
device -> mVolumeController.registerCallback(ThreadUtils.getBackgroundExecutor(),
|
|
||||||
device.getDevice()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAmbientChanged(@NonNull BluetoothDevice device, int gainSettings) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "onAmbientChanged, value:" + gainSettings + ", device:" + device);
|
|
||||||
}
|
|
||||||
Data data = mLocalDataManager.get(device);
|
|
||||||
boolean isInitiatedFromUi = (isControlExpanded() && data.ambient() == gainSettings)
|
|
||||||
|| (!isControlExpanded() && data.groupAmbient() == gainSettings);
|
|
||||||
if (isInitiatedFromUi) {
|
|
||||||
// The change is initiated from UI, no need to update UI
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have to check if we need to expand the controls by getting all remote
|
|
||||||
// device's ambient value, delay for a while to wait all remote devices update
|
|
||||||
// to the latest value to avoid unnecessary expand action.
|
|
||||||
mContext.getMainThreadHandler().postDelayed(this::refresh, 1200L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onMuteChanged(@NonNull BluetoothDevice device, int mute) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "onMuteChanged, mute:" + mute + ", device:" + device);
|
|
||||||
}
|
|
||||||
boolean isInitiatedFromUi = (isControlMuted() && mute == MUTE_MUTED)
|
|
||||||
|| (!isControlMuted() && mute == MUTE_NOT_MUTED);
|
|
||||||
if (isInitiatedFromUi) {
|
|
||||||
// The change is initiated from UI, no need to update UI
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We have to check if we need to mute the devices by getting all remote
|
|
||||||
// device's mute state, delay for a while to wait all remote devices update
|
|
||||||
// to the latest value.
|
|
||||||
mContext.getMainThreadHandler().postDelayed(this::refresh, 1200L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCommandFailed(@NonNull BluetoothDevice device) {
|
|
||||||
Log.w(TAG, "onCommandFailed, device:" + device);
|
|
||||||
mContext.getMainExecutor().execute(() -> {
|
|
||||||
showErrorToast();
|
|
||||||
refresh();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadDevices() {
|
|
||||||
mSideToDeviceMap.clear();
|
|
||||||
mCachedDevices.clear();
|
|
||||||
if (VALID_SIDES.contains(mCachedDevice.getDeviceSide())
|
|
||||||
&& mCachedDevice.getBondState() == BOND_BONDED) {
|
|
||||||
mSideToDeviceMap.put(mCachedDevice.getDeviceSide(), mCachedDevice.getDevice());
|
|
||||||
mCachedDevices.add(mCachedDevice);
|
|
||||||
}
|
|
||||||
for (CachedBluetoothDevice memberDevice : mCachedDevice.getMemberDevice()) {
|
|
||||||
if (VALID_SIDES.contains(memberDevice.getDeviceSide())
|
|
||||||
&& memberDevice.getBondState() == BOND_BONDED) {
|
|
||||||
mSideToDeviceMap.put(memberDevice.getDeviceSide(), memberDevice.getDevice());
|
|
||||||
mCachedDevices.add(memberDevice);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
createAmbientVolumePreference();
|
|
||||||
createSliderPreferences();
|
|
||||||
if (mPreference != null) {
|
|
||||||
mPreference.setExpandable(mSideToDeviceMap.size() > 1);
|
|
||||||
mPreference.setSliders((mSideToSliderMap));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createAmbientVolumePreference() {
|
|
||||||
if (mPreference != null || mDeviceControls == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mPreference = new AmbientVolumePreference(mDeviceControls.getContext());
|
|
||||||
mPreference.setKey(KEY_AMBIENT_VOLUME);
|
|
||||||
mPreference.setOrder(ORDER_AMBIENT_VOLUME);
|
|
||||||
mPreference.setOnIconClickListener(
|
|
||||||
new AmbientVolumePreference.OnIconClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onExpandIconClick() {
|
|
||||||
mSideToDeviceMap.forEach((s, d) -> {
|
|
||||||
if (!isControlMuted()) {
|
|
||||||
// Apply previous collapsed/expanded volume to remote device
|
|
||||||
Data data = mLocalDataManager.get(d);
|
|
||||||
int volume = isControlExpanded()
|
|
||||||
? data.ambient() : data.groupAmbient();
|
|
||||||
mVolumeController.setAmbient(d, volume);
|
|
||||||
}
|
|
||||||
// Update new value to local data
|
|
||||||
mLocalDataManager.updateAmbientControlExpanded(d, isControlExpanded());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onAmbientVolumeIconClick() {
|
|
||||||
if (!isControlMuted()) {
|
|
||||||
loadLocalDataToUi();
|
|
||||||
}
|
|
||||||
for (BluetoothDevice device : mSideToDeviceMap.values()) {
|
|
||||||
mVolumeController.setMuted(device, isControlMuted());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (mDeviceControls.findPreference(mPreference.getKey()) == null) {
|
|
||||||
mDeviceControls.addPreference(mPreference);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createSliderPreferences() {
|
|
||||||
mSideToDeviceMap.forEach((s, d) ->
|
|
||||||
createSliderPreference(s, ORDER_AMBIENT_VOLUME_CONTROL_SEPARATED + s));
|
|
||||||
createSliderPreference(SIDE_UNIFIED, ORDER_AMBIENT_VOLUME_CONTROL_UNIFIED);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createSliderPreference(int side, int order) {
|
|
||||||
if (mSideToSliderMap.containsKey(side) || mDeviceControls == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
SeekBarPreference preference = new SeekBarPreference(mDeviceControls.getContext());
|
|
||||||
preference.setKey(KEY_AMBIENT_VOLUME_SLIDER + "_" + side);
|
|
||||||
preference.setOrder(order);
|
|
||||||
preference.setOnPreferenceChangeListener(this);
|
|
||||||
if (side == SIDE_LEFT) {
|
|
||||||
preference.setTitle(mContext.getString(R.string.bluetooth_ambient_volume_control_left));
|
|
||||||
} else if (side == SIDE_RIGHT) {
|
|
||||||
preference.setTitle(
|
|
||||||
mContext.getString(R.string.bluetooth_ambient_volume_control_right));
|
|
||||||
}
|
|
||||||
mSideToSliderMap.put(side, preference);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Refreshes the control UI visibility and enabled state. */
|
|
||||||
private void refreshControlUi() {
|
|
||||||
if (mPreference != null) {
|
|
||||||
boolean isAnySliderEnabled = false;
|
|
||||||
for (Map.Entry<Integer, BluetoothDevice> entry : mSideToDeviceMap.entrySet()) {
|
|
||||||
final int side = entry.getKey();
|
|
||||||
final BluetoothDevice device = entry.getValue();
|
|
||||||
final boolean enabled = isDeviceConnectedToVcp(device)
|
|
||||||
&& mVolumeController.isAmbientControlAvailable(device);
|
|
||||||
isAnySliderEnabled |= enabled;
|
|
||||||
mPreference.setSliderEnabled(side, enabled);
|
|
||||||
}
|
|
||||||
mPreference.setSliderEnabled(SIDE_UNIFIED, isAnySliderEnabled);
|
|
||||||
mPreference.updateLayout();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sets the volume to the corresponding control slider. */
|
|
||||||
private void setVolumeIfValid(int side, int volume) {
|
|
||||||
if (volume == INVALID_VOLUME) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mPreference != null) {
|
|
||||||
mPreference.setSliderValue(side, volume);
|
|
||||||
}
|
|
||||||
// Update new value to local data
|
|
||||||
if (side == SIDE_UNIFIED) {
|
|
||||||
mSideToDeviceMap.forEach((s, d) -> mLocalDataManager.updateGroupAmbient(d, volume));
|
|
||||||
} else {
|
|
||||||
mLocalDataManager.updateAmbient(mSideToDeviceMap.get(side), volume);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadLocalDataToUi() {
|
|
||||||
mSideToDeviceMap.forEach((s, d) -> loadLocalDataToUi(d));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadLocalDataToUi(BluetoothDevice device) {
|
|
||||||
final Data data = mLocalDataManager.get(device);
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "loadLocalDataToUi, data=" + data + ", device=" + device);
|
|
||||||
}
|
|
||||||
final int side = mSideToDeviceMap.inverse().getOrDefault(device, SIDE_INVALID);
|
|
||||||
if (isDeviceConnectedToVcp(device) && !isControlMuted()) {
|
|
||||||
setVolumeIfValid(side, data.ambient());
|
|
||||||
setVolumeIfValid(SIDE_UNIFIED, data.groupAmbient());
|
|
||||||
}
|
|
||||||
setControlExpanded(data.ambientControlExpanded());
|
|
||||||
refreshControlUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadRemoteDataToUi() {
|
|
||||||
BluetoothDevice leftDevice = mSideToDeviceMap.get(SIDE_LEFT);
|
|
||||||
AmbientVolumeController.RemoteAmbientState leftState =
|
|
||||||
mVolumeController.refreshAmbientState(leftDevice);
|
|
||||||
BluetoothDevice rightDevice = mSideToDeviceMap.get(SIDE_RIGHT);
|
|
||||||
AmbientVolumeController.RemoteAmbientState rightState =
|
|
||||||
mVolumeController.refreshAmbientState(rightDevice);
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "loadRemoteDataToUi, left=" + leftState + ", right=" + rightState);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mPreference != null) {
|
|
||||||
mSideToDeviceMap.forEach((side, device) -> {
|
|
||||||
int ambientMax = mVolumeController.getAmbientMax(device);
|
|
||||||
int ambientMin = mVolumeController.getAmbientMin(device);
|
|
||||||
if (ambientMin != ambientMax) {
|
|
||||||
mPreference.setSliderRange(side, ambientMin, ambientMax);
|
|
||||||
mPreference.setSliderRange(SIDE_UNIFIED, ambientMin, ambientMax);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update ambient volume
|
|
||||||
final int leftAmbient = leftState != null ? leftState.gainSetting() : INVALID_VOLUME;
|
|
||||||
final int rightAmbient = rightState != null ? rightState.gainSetting() : INVALID_VOLUME;
|
|
||||||
if (isControlExpanded()) {
|
|
||||||
setVolumeIfValid(SIDE_LEFT, leftAmbient);
|
|
||||||
setVolumeIfValid(SIDE_RIGHT, rightAmbient);
|
|
||||||
} else {
|
|
||||||
if (leftAmbient != rightAmbient && leftAmbient != INVALID_VOLUME
|
|
||||||
&& rightAmbient != INVALID_VOLUME) {
|
|
||||||
setVolumeIfValid(SIDE_LEFT, leftAmbient);
|
|
||||||
setVolumeIfValid(SIDE_RIGHT, rightAmbient);
|
|
||||||
setControlExpanded(true);
|
|
||||||
} else {
|
|
||||||
int unifiedAmbient = leftAmbient != INVALID_VOLUME ? leftAmbient : rightAmbient;
|
|
||||||
setVolumeIfValid(SIDE_UNIFIED, unifiedAmbient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Initialize local data between side and group value
|
|
||||||
initLocalDataIfNeeded();
|
|
||||||
|
|
||||||
// Update mute state
|
|
||||||
boolean mutable = true;
|
|
||||||
boolean muted = true;
|
|
||||||
if (isDeviceConnectedToVcp(leftDevice) && leftState != null) {
|
|
||||||
mutable &= leftState.isMutable();
|
|
||||||
muted &= leftState.isMuted();
|
|
||||||
}
|
|
||||||
if (isDeviceConnectedToVcp(rightDevice) && rightState != null) {
|
|
||||||
mutable &= rightState.isMutable();
|
|
||||||
muted &= rightState.isMuted();
|
|
||||||
}
|
|
||||||
if (mPreference != null) {
|
|
||||||
mPreference.setMutable(mutable);
|
|
||||||
mPreference.setMuted(muted);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure remote device mute state is synced
|
|
||||||
syncMuteStateIfNeeded(leftDevice, leftState, muted);
|
|
||||||
syncMuteStateIfNeeded(rightDevice, rightState, muted);
|
|
||||||
|
|
||||||
refreshControlUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Check if any device in the group has valid ambient control points */
|
|
||||||
private boolean isAmbientControlAvailable() {
|
|
||||||
for (BluetoothDevice device : mSideToDeviceMap.values()) {
|
|
||||||
// Found ambient local data for this device, show the ambient control
|
|
||||||
if (mLocalDataManager.get(device).hasAmbientData()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Found remote ambient control points on this device, show the ambient control
|
|
||||||
if (mVolumeController.isAmbientControlAvailable(device)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isControlExpanded() {
|
|
||||||
return mPreference != null && mPreference.isExpanded();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setControlExpanded(boolean expanded) {
|
|
||||||
if (mPreference != null && mPreference.isExpanded() != expanded) {
|
|
||||||
mPreference.setExpanded(expanded);
|
|
||||||
}
|
|
||||||
mSideToDeviceMap.forEach((s, d) -> {
|
|
||||||
// Update new value to local data
|
|
||||||
mLocalDataManager.updateAmbientControlExpanded(d, expanded);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isControlMuted() {
|
|
||||||
return mPreference != null && mPreference.isMuted();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initLocalDataIfNeeded() {
|
|
||||||
int smallerVolumeAmongGroup = Integer.MAX_VALUE;
|
|
||||||
for (BluetoothDevice device : mSideToDeviceMap.values()) {
|
|
||||||
Data data = mLocalDataManager.get(device);
|
|
||||||
if (data.ambient() != INVALID_VOLUME) {
|
|
||||||
smallerVolumeAmongGroup = Math.min(data.ambient(), smallerVolumeAmongGroup);
|
|
||||||
} else if (data.groupAmbient() != INVALID_VOLUME) {
|
|
||||||
// Initialize side ambient from group ambient value
|
|
||||||
mLocalDataManager.updateAmbient(device, data.groupAmbient());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (smallerVolumeAmongGroup != Integer.MAX_VALUE) {
|
|
||||||
for (BluetoothDevice device : mSideToDeviceMap.values()) {
|
|
||||||
Data data = mLocalDataManager.get(device);
|
|
||||||
if (data.groupAmbient() == INVALID_VOLUME) {
|
|
||||||
// Initialize group ambient from smaller side ambient value
|
|
||||||
mLocalDataManager.updateGroupAmbient(device, smallerVolumeAmongGroup);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void syncMuteStateIfNeeded(@Nullable BluetoothDevice device,
|
|
||||||
@Nullable AmbientVolumeController.RemoteAmbientState state, boolean muted) {
|
|
||||||
if (isDeviceConnectedToVcp(device) && state != null && state.isMutable()) {
|
|
||||||
if (state.isMuted() != muted) {
|
|
||||||
mVolumeController.setMuted(device, muted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isDeviceConnectedToVcp(@Nullable BluetoothDevice device) {
|
|
||||||
return device != null && device.isConnected()
|
|
||||||
&& mBluetoothManager.getProfileManager().getVolumeControlProfile()
|
|
||||||
.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showErrorToast() {
|
|
||||||
if (mToast != null) {
|
|
||||||
mToast.cancel();
|
|
||||||
}
|
|
||||||
mToast = Toast.makeText(mContext, R.string.bluetooth_ambient_volume_error,
|
|
||||||
Toast.LENGTH_SHORT);
|
|
||||||
mToast.show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import com.android.settingslib.datastore.SettingsSystemStore
|
|||||||
import com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX
|
import com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX
|
||||||
import com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MIN
|
import com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MIN
|
||||||
import com.android.settingslib.display.BrightnessUtils.convertLinearToGammaFloat
|
import com.android.settingslib.display.BrightnessUtils.convertLinearToGammaFloat
|
||||||
import com.android.settingslib.metadata.PersistentPreference
|
import com.android.settingslib.metadata.FloatPersistentPreference
|
||||||
import com.android.settingslib.metadata.PreferenceMetadata
|
import com.android.settingslib.metadata.PreferenceMetadata
|
||||||
import com.android.settingslib.metadata.PreferenceSummaryProvider
|
import com.android.settingslib.metadata.PreferenceSummaryProvider
|
||||||
import com.android.settingslib.metadata.ReadWritePermit
|
import com.android.settingslib.metadata.ReadWritePermit
|
||||||
@@ -52,7 +52,7 @@ import java.text.NumberFormat
|
|||||||
// LINT.IfChange
|
// LINT.IfChange
|
||||||
class BrightnessLevelPreference :
|
class BrightnessLevelPreference :
|
||||||
PreferenceMetadata,
|
PreferenceMetadata,
|
||||||
PersistentPreference<Float>,
|
FloatPersistentPreference,
|
||||||
PreferenceBinding,
|
PreferenceBinding,
|
||||||
PreferenceRestrictionMixin,
|
PreferenceRestrictionMixin,
|
||||||
PreferenceSummaryProvider,
|
PreferenceSummaryProvider,
|
||||||
@@ -78,7 +78,7 @@ class BrightnessLevelPreference :
|
|||||||
override val useAdminDisabledSummary: Boolean
|
override val useAdminDisabledSummary: Boolean
|
||||||
get() = true
|
get() = true
|
||||||
|
|
||||||
override fun intent(context: Context) =
|
override fun intent(context: Context): Intent? =
|
||||||
Intent(ACTION_SHOW_BRIGHTNESS_DIALOG)
|
Intent(ACTION_SHOW_BRIGHTNESS_DIALOG)
|
||||||
.setPackage(Utils.SYSTEMUI_PACKAGE_NAME)
|
.setPackage(Utils.SYSTEMUI_PACKAGE_NAME)
|
||||||
.putExtra(
|
.putExtra(
|
||||||
|
|||||||
@@ -109,12 +109,9 @@ public class ActionDisabledByAdminDialog extends Activity
|
|||||||
}
|
}
|
||||||
if (enforcingAdmin.getAuthority() instanceof UnknownAuthority authority
|
if (enforcingAdmin.getAuthority() instanceof UnknownAuthority authority
|
||||||
&& ADVANCED_PROTECTION_SYSTEM_ENTITY.equals(authority.getName())) {
|
&& ADVANCED_PROTECTION_SYSTEM_ENTITY.equals(authority.getName())) {
|
||||||
AdvancedProtectionManager apm = getSystemService(AdvancedProtectionManager.class);
|
Intent apmSupportIntent = AdvancedProtectionManager
|
||||||
if (apm == null) {
|
.createSupportIntentForPolicyIdentifierOrRestriction(restriction,
|
||||||
return;
|
AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_UNKNOWN);
|
||||||
}
|
|
||||||
Intent apmSupportIntent = apm.createSupportIntentForPolicyIdentifierOrRestriction(
|
|
||||||
restriction, /* type */ null);
|
|
||||||
startActivityAsUser(apmSupportIntent, UserHandle.of(userId));
|
startActivityAsUser(apmSupportIntent, UserHandle.of(userId));
|
||||||
finish();
|
finish();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ import android.util.Pair;
|
|||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.loader.app.LoaderManager;
|
import androidx.loader.app.LoaderManager;
|
||||||
import androidx.loader.content.Loader;
|
import androidx.loader.content.Loader;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
@@ -149,6 +151,13 @@ public class PowerUsageAdvanced extends PowerUsageBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RecyclerView.Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
|
||||||
|
final RecyclerView.Adapter adapter = super.onCreateAdapter(preferenceScreen);
|
||||||
|
adapter.setHasStableIds(true);
|
||||||
|
return adapter;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
|
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
|
||||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ import static android.view.PointerIcon.POINTER_ICON_VECTOR_STYLE_FILL_RED;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.graphics.drawable.LayerDrawable;
|
||||||
|
import android.graphics.drawable.StateListDrawable;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.PointerIcon;
|
import android.view.PointerIcon;
|
||||||
@@ -41,6 +44,11 @@ import com.android.settings.R;
|
|||||||
|
|
||||||
|
|
||||||
public class PointerFillStylePreference extends Preference {
|
public class PointerFillStylePreference extends Preference {
|
||||||
|
private static final int[] STATE_HOVERED_SELECTED =
|
||||||
|
new int[]{android.R.attr.state_hovered, android.R.attr.state_selected};
|
||||||
|
private static final int[] STATE_SELECTED = new int[]{android.R.attr.state_selected};
|
||||||
|
private static final int[] STATE_HOVERED = new int[]{android.R.attr.state_hovered};
|
||||||
|
private static final int[] STATE_DEFAULT = new int[]{};
|
||||||
|
|
||||||
@Nullable private LinearLayout mButtonHolder;
|
@Nullable private LinearLayout mButtonHolder;
|
||||||
|
|
||||||
@@ -82,11 +90,7 @@ public class PointerFillStylePreference extends Preference {
|
|||||||
if (button == null) {
|
if (button == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int[] attrs = {com.android.internal.R.attr.pointerIconVectorFill};
|
tintButtonByStyle(button, style);
|
||||||
try (TypedArray ta = getContext().obtainStyledAttributes(
|
|
||||||
PointerIcon.vectorFillStyleToResource(style), attrs)) {
|
|
||||||
button.getBackground().setTint(ta.getColor(0, Color.BLACK));
|
|
||||||
}
|
|
||||||
button.setOnClickListener(
|
button.setOnClickListener(
|
||||||
(v) -> {
|
(v) -> {
|
||||||
getPreferenceDataStore().putInt(Settings.System.POINTER_FILL_STYLE, style);
|
getPreferenceDataStore().putInt(Settings.System.POINTER_FILL_STYLE, style);
|
||||||
@@ -96,6 +100,32 @@ public class PointerFillStylePreference extends Preference {
|
|||||||
button.setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_ARROW));
|
button.setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_ARROW));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tintButtonByStyle(ImageView button, int style) {
|
||||||
|
int[] attrs = {com.android.internal.R.attr.pointerIconVectorFill};
|
||||||
|
try (TypedArray ta = getContext().obtainStyledAttributes(
|
||||||
|
PointerIcon.vectorFillStyleToResource(style), attrs)) {
|
||||||
|
// Index 0, as there is only one attribute returned here.
|
||||||
|
int color = ta.getColor(/* index= */ 0, Color.BLACK);
|
||||||
|
StateListDrawable stateListDrawable = (StateListDrawable) button.getDrawable();
|
||||||
|
tintDrawableByLayerId(stateListDrawable, STATE_HOVERED_SELECTED,
|
||||||
|
R.id.tintableCircleHoveredSelected, color);
|
||||||
|
tintDrawableByLayerId(stateListDrawable, STATE_SELECTED, R.id.tintableCircleSelected,
|
||||||
|
color);
|
||||||
|
tintDrawableByLayerId(stateListDrawable, STATE_HOVERED, R.id.tintableCircleHovered,
|
||||||
|
color);
|
||||||
|
tintDrawableByLayerId(stateListDrawable, STATE_DEFAULT, R.id.tintableCircleDefault,
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void tintDrawableByLayerId(StateListDrawable stateListDrawable, int[] stateSet,
|
||||||
|
int layerId, int color) {
|
||||||
|
int index = stateListDrawable.findStateDrawableIndex(stateSet);
|
||||||
|
LayerDrawable layerDrawable = (LayerDrawable) stateListDrawable.getStateDrawable(index);
|
||||||
|
Drawable drawable = layerDrawable.findDrawableByLayerId(layerId);
|
||||||
|
drawable.setTint(color);
|
||||||
|
}
|
||||||
|
|
||||||
private void setButtonChecked(int id) {
|
private void setButtonChecked(int id) {
|
||||||
if (mButtonHolder == null) {
|
if (mButtonHolder == null) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import java.util.Collection;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
@@ -345,6 +346,7 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions
|
|||||||
List<SubscriptionInfoEntity> availableSubInfoEntityList) {
|
List<SubscriptionInfoEntity> availableSubInfoEntityList) {
|
||||||
List<SubscriptionInfoEntity> activeSubInfoEntityList =
|
List<SubscriptionInfoEntity> activeSubInfoEntityList =
|
||||||
availableSubInfoEntityList.stream()
|
availableSubInfoEntityList.stream()
|
||||||
|
.filter(entity -> Objects.nonNull(entity))
|
||||||
.filter(SubscriptionInfoEntity::isActiveSubscription)
|
.filter(SubscriptionInfoEntity::isActiveSubscription)
|
||||||
.filter(SubscriptionInfoEntity::isSubscriptionVisible)
|
.filter(SubscriptionInfoEntity::isSubscriptionVisible)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.security;
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.android.settings.R
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
|
class ActionDisabledByAdvancedProtectionDialog : Activity(), DialogInterface.OnDismissListener {
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
val dialogView = layoutInflater.inflate(R.layout.support_details_dialog, null) as ViewGroup
|
||||||
|
val builder = AlertDialog.Builder(this)
|
||||||
|
.setPositiveButton(R.string.okay, null)
|
||||||
|
.setView(dialogView)
|
||||||
|
.setOnDismissListener(this)
|
||||||
|
initializeDialogView(dialogView)
|
||||||
|
builder.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initializeDialogView(dialogView: View) {
|
||||||
|
setSupportTitle(dialogView)
|
||||||
|
setSupportDetails(dialogView)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSupportTitle(root: View) {
|
||||||
|
val titleView: TextView = root.findViewById(R.id.admin_support_dialog_title) ?: return
|
||||||
|
titleView.setText(R.string.disabled_by_advanced_protection_title)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setSupportDetails(root: View) {
|
||||||
|
val textView: TextView = root.findViewById(R.id.admin_support_msg)
|
||||||
|
textView.setText(R.string.disabled_by_advanced_protection_message)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -204,5 +204,7 @@ private fun PreferenceProto.toMetadata(
|
|||||||
.setWritable(persistent)
|
.setWritable(persistent)
|
||||||
.setLaunchIntent(launchIntent.toIntent())
|
.setLaunchIntent(launchIntent.toIntent())
|
||||||
.setWriteSensitivity(sensitivity)
|
.setWriteSensitivity(sensitivity)
|
||||||
|
.setReadPermissions(readPermissionsList)
|
||||||
|
.setWritePermissions(writePermissionsList)
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,9 +142,13 @@ public class SeekBarPreference extends RestrictedPreference
|
|||||||
mSeekBar.setContentDescription(mSeekBarContentDescription);
|
mSeekBar.setContentDescription(mSeekBarContentDescription);
|
||||||
} else if (!TextUtils.isEmpty(title)) {
|
} else if (!TextUtils.isEmpty(title)) {
|
||||||
mSeekBar.setContentDescription(title);
|
mSeekBar.setContentDescription(title);
|
||||||
|
} else {
|
||||||
|
mSeekBar.setContentDescription(null);
|
||||||
}
|
}
|
||||||
if (!TextUtils.isEmpty(mSeekBarStateDescription)) {
|
if (!TextUtils.isEmpty(mSeekBarStateDescription)) {
|
||||||
mSeekBar.setStateDescription(mSeekBarStateDescription);
|
mSeekBar.setStateDescription(mSeekBarStateDescription);
|
||||||
|
} else {
|
||||||
|
mSeekBar.setStateDescription(null);
|
||||||
}
|
}
|
||||||
if (mSeekBar instanceof DefaultIndicatorSeekBar) {
|
if (mSeekBar instanceof DefaultIndicatorSeekBar) {
|
||||||
((DefaultIndicatorSeekBar) mSeekBar).setDefaultProgress(mDefaultProgress);
|
((DefaultIndicatorSeekBar) mSeekBar).setDefaultProgress(mDefaultProgress);
|
||||||
|
|||||||
@@ -162,10 +162,10 @@ class WepNetworksPreferenceController(context: Context, preferenceKey: String) :
|
|||||||
emit(aapmManager?.isAdvancedProtectionEnabled ?: false) }.flowOn(Dispatchers.Default)
|
emit(aapmManager?.isAdvancedProtectionEnabled ?: false) }.flowOn(Dispatchers.Default)
|
||||||
|
|
||||||
private fun startSupportIntent() {
|
private fun startSupportIntent() {
|
||||||
aapmManager?.createSupportIntent(
|
AdvancedProtectionManager.createSupportIntent(
|
||||||
AdvancedProtectionManager.FEATURE_ID_DISALLOW_WEP,
|
AdvancedProtectionManager.FEATURE_ID_DISALLOW_WEP,
|
||||||
AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_DISABLED_SETTING
|
AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_DISABLED_SETTING
|
||||||
)?.let { mContext.startActivity(it) }
|
).let { mContext.startActivity(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val wepAllowedFlow =
|
val wepAllowedFlow =
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ public class HighContrastTextMigrationReceiverTest {
|
|||||||
|
|
||||||
ShadowNotification shadowNotification = Shadows.shadowOf(notification);
|
ShadowNotification shadowNotification = Shadows.shadowOf(notification);
|
||||||
assertThat(shadowNotification.getContentTitle()).isEqualTo(mContext.getString(
|
assertThat(shadowNotification.getContentTitle()).isEqualTo(mContext.getString(
|
||||||
R.string.accessibility_toggle_high_text_contrast_preference_title));
|
R.string.accessibility_notification_high_contrast_text_title));
|
||||||
assertThat(shadowNotification.getContentText()).isEqualTo(
|
assertThat(shadowNotification.getContentText()).isEqualTo(
|
||||||
mContext.getString(R.string.accessibility_notification_high_contrast_text_content));
|
mContext.getString(R.string.accessibility_notification_high_contrast_text_content));
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,10 @@ import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_R
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -40,6 +42,7 @@ import androidx.test.core.app.ApplicationProvider;
|
|||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.widget.SeekBarPreference;
|
import com.android.settings.widget.SeekBarPreference;
|
||||||
|
import com.android.settingslib.bluetooth.AmbientVolumeUi;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
@@ -69,14 +72,14 @@ public class AmbientVolumePreferenceTest {
|
|||||||
@Spy
|
@Spy
|
||||||
private Context mContext = ApplicationProvider.getApplicationContext();
|
private Context mContext = ApplicationProvider.getApplicationContext();
|
||||||
@Mock
|
@Mock
|
||||||
private AmbientVolumePreference.OnIconClickListener mListener;
|
private AmbientVolumeUi.AmbientVolumeUiListener mListener;
|
||||||
@Mock
|
@Mock
|
||||||
private View mItemView;
|
private View mItemView;
|
||||||
|
|
||||||
private AmbientVolumePreference mPreference;
|
private AmbientVolumePreference mPreference;
|
||||||
private ImageView mExpandIcon;
|
private ImageView mExpandIcon;
|
||||||
private ImageView mVolumeIcon;
|
private ImageView mVolumeIcon;
|
||||||
private final Map<Integer, SeekBarPreference> mSideToSlidersMap = new ArrayMap<>();
|
private final Map<Integer, BluetoothDevice> mSideToDeviceMap = new ArrayMap<>();
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -84,13 +87,27 @@ public class AmbientVolumePreferenceTest {
|
|||||||
PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext);
|
PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext);
|
||||||
mPreference = new AmbientVolumePreference(mContext);
|
mPreference = new AmbientVolumePreference(mContext);
|
||||||
mPreference.setKey(KEY_AMBIENT_VOLUME);
|
mPreference.setKey(KEY_AMBIENT_VOLUME);
|
||||||
mPreference.setOnIconClickListener(mListener);
|
mPreference.setListener(mListener);
|
||||||
mPreference.setExpandable(true);
|
mPreference.setExpandable(true);
|
||||||
mPreference.setMutable(true);
|
mPreference.setMutable(true);
|
||||||
preferenceScreen.addPreference(mPreference);
|
preferenceScreen.addPreference(mPreference);
|
||||||
|
|
||||||
prepareSliders();
|
prepareDevices();
|
||||||
mPreference.setSliders(mSideToSlidersMap);
|
mPreference.setupSliders(mSideToDeviceMap);
|
||||||
|
mPreference.getSliders().forEach((side, slider) -> {
|
||||||
|
slider.setMin(0);
|
||||||
|
slider.setMax(4);
|
||||||
|
if (side == SIDE_LEFT) {
|
||||||
|
slider.setKey(KEY_LEFT_SLIDER);
|
||||||
|
slider.setProgress(TEST_LEFT_VOLUME_LEVEL);
|
||||||
|
} else if (side == SIDE_RIGHT) {
|
||||||
|
slider.setKey(KEY_RIGHT_SLIDER);
|
||||||
|
slider.setProgress(TEST_RIGHT_VOLUME_LEVEL);
|
||||||
|
} else {
|
||||||
|
slider.setKey(KEY_UNIFIED_SLIDER);
|
||||||
|
slider.setProgress(TEST_UNIFIED_VOLUME_LEVEL);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
mExpandIcon = new ImageView(mContext);
|
mExpandIcon = new ImageView(mContext);
|
||||||
mVolumeIcon = new ImageView(mContext);
|
mVolumeIcon = new ImageView(mContext);
|
||||||
@@ -206,33 +223,16 @@ public class AmbientVolumePreferenceTest {
|
|||||||
|
|
||||||
private void assertControlUiCorrect() {
|
private void assertControlUiCorrect() {
|
||||||
final boolean expanded = mPreference.isExpanded();
|
final boolean expanded = mPreference.isExpanded();
|
||||||
assertThat(mSideToSlidersMap.get(SIDE_UNIFIED).isVisible()).isEqualTo(!expanded);
|
Map<Integer, SeekBarPreference> sliders = mPreference.getSliders();
|
||||||
assertThat(mSideToSlidersMap.get(SIDE_LEFT).isVisible()).isEqualTo(expanded);
|
assertThat(sliders.get(SIDE_UNIFIED).isVisible()).isEqualTo(!expanded);
|
||||||
assertThat(mSideToSlidersMap.get(SIDE_RIGHT).isVisible()).isEqualTo(expanded);
|
assertThat(sliders.get(SIDE_LEFT).isVisible()).isEqualTo(expanded);
|
||||||
|
assertThat(sliders.get(SIDE_RIGHT).isVisible()).isEqualTo(expanded);
|
||||||
final float rotation = expanded ? ROTATION_EXPANDED : ROTATION_COLLAPSED;
|
final float rotation = expanded ? ROTATION_EXPANDED : ROTATION_COLLAPSED;
|
||||||
assertThat(mExpandIcon.getRotation()).isEqualTo(rotation);
|
assertThat(mExpandIcon.getRotation()).isEqualTo(rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareSliders() {
|
private void prepareDevices() {
|
||||||
prepareSlider(SIDE_UNIFIED);
|
mSideToDeviceMap.put(SIDE_LEFT, mock(BluetoothDevice.class));
|
||||||
prepareSlider(SIDE_LEFT);
|
mSideToDeviceMap.put(SIDE_RIGHT, mock(BluetoothDevice.class));
|
||||||
prepareSlider(SIDE_RIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prepareSlider(int side) {
|
|
||||||
SeekBarPreference slider = new SeekBarPreference(mContext);
|
|
||||||
slider.setMin(0);
|
|
||||||
slider.setMax(4);
|
|
||||||
if (side == SIDE_LEFT) {
|
|
||||||
slider.setKey(KEY_LEFT_SLIDER);
|
|
||||||
slider.setProgress(TEST_LEFT_VOLUME_LEVEL);
|
|
||||||
} else if (side == SIDE_RIGHT) {
|
|
||||||
slider.setKey(KEY_RIGHT_SLIDER);
|
|
||||||
slider.setProgress(TEST_RIGHT_VOLUME_LEVEL);
|
|
||||||
} else {
|
|
||||||
slider.setKey(KEY_UNIFIED_SLIDER);
|
|
||||||
slider.setProgress(TEST_UNIFIED_VOLUME_LEVEL);
|
|
||||||
}
|
|
||||||
mSideToSlidersMap.put(side, slider);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,46 +16,25 @@
|
|||||||
|
|
||||||
package com.android.settings.bluetooth;
|
package com.android.settings.bluetooth;
|
||||||
|
|
||||||
import static android.bluetooth.AudioInputControl.MUTE_DISABLED;
|
|
||||||
import static android.bluetooth.AudioInputControl.MUTE_NOT_MUTED;
|
|
||||||
import static android.bluetooth.AudioInputControl.MUTE_MUTED;
|
|
||||||
import static android.bluetooth.BluetoothDevice.BOND_BONDED;
|
|
||||||
|
|
||||||
import static com.android.settings.bluetooth.BluetoothDetailsAmbientVolumePreferenceController.KEY_AMBIENT_VOLUME;
|
import static com.android.settings.bluetooth.BluetoothDetailsAmbientVolumePreferenceController.KEY_AMBIENT_VOLUME;
|
||||||
import static com.android.settings.bluetooth.BluetoothDetailsAmbientVolumePreferenceController.KEY_AMBIENT_VOLUME_SLIDER;
|
|
||||||
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.KEY_HEARING_DEVICE_GROUP;
|
import static com.android.settings.bluetooth.BluetoothDetailsHearingDeviceController.KEY_HEARING_DEVICE_GROUP;
|
||||||
import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_LEFT;
|
|
||||||
import static com.android.settingslib.bluetooth.HearingAidInfo.DeviceSide.SIDE_RIGHT;
|
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.Mockito.atLeastOnce;
|
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.robolectric.Shadows.shadowOf;
|
|
||||||
|
|
||||||
import android.bluetooth.BluetoothDevice;
|
|
||||||
import android.bluetooth.BluetoothProfile;
|
|
||||||
import android.content.ContentResolver;
|
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
|
||||||
import android.provider.Settings;
|
|
||||||
|
|
||||||
import androidx.preference.PreferenceCategory;
|
import androidx.preference.PreferenceCategory;
|
||||||
|
|
||||||
import com.android.settings.testutils.shadow.ShadowThreadUtils;
|
import com.android.settings.testutils.shadow.ShadowThreadUtils;
|
||||||
import com.android.settings.widget.SeekBarPreference;
|
import com.android.settingslib.bluetooth.AmbientVolumeUiController;
|
||||||
import com.android.settingslib.bluetooth.AmbientVolumeController;
|
|
||||||
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
import com.android.settingslib.bluetooth.BluetoothEventManager;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
|
||||||
import com.android.settingslib.bluetooth.HearingDeviceLocalDataManager;
|
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||||
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
import com.android.settingslib.bluetooth.VolumeControlProfile;
|
||||||
@@ -69,41 +48,19 @@ import org.mockito.junit.MockitoJUnit;
|
|||||||
import org.mockito.junit.MockitoRule;
|
import org.mockito.junit.MockitoRule;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.annotation.Implementation;
|
|
||||||
import org.robolectric.annotation.Implements;
|
|
||||||
import org.robolectric.shadows.ShadowSettings;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
/** Tests for {@link BluetoothDetailsAmbientVolumePreferenceController}. */
|
/** Tests for {@link BluetoothDetailsAmbientVolumePreferenceController}. */
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
@Config(shadows = {
|
@Config(shadows = {
|
||||||
BluetoothDetailsAmbientVolumePreferenceControllerTest.ShadowGlobal.class,
|
|
||||||
ShadowThreadUtils.class
|
ShadowThreadUtils.class
|
||||||
})
|
})
|
||||||
public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
||||||
BluetoothDetailsControllerTestBase {
|
BluetoothDetailsControllerTestBase {
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||||
|
|
||||||
private static final String LEFT_CONTROL_KEY = KEY_AMBIENT_VOLUME_SLIDER + "_" + SIDE_LEFT;
|
|
||||||
private static final String RIGHT_CONTROL_KEY = KEY_AMBIENT_VOLUME_SLIDER + "_" + SIDE_RIGHT;
|
|
||||||
private static final String TEST_ADDRESS = "00:00:00:00:11";
|
|
||||||
private static final String TEST_MEMBER_ADDRESS = "00:00:00:00:22";
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private CachedBluetoothDevice mCachedMemberDevice;
|
|
||||||
@Mock
|
|
||||||
private BluetoothDevice mDevice;
|
|
||||||
@Mock
|
|
||||||
private BluetoothDevice mMemberDevice;
|
|
||||||
@Mock
|
|
||||||
private HearingDeviceLocalDataManager mLocalDataManager;
|
|
||||||
@Mock
|
@Mock
|
||||||
private LocalBluetoothManager mBluetoothManager;
|
private LocalBluetoothManager mBluetoothManager;
|
||||||
@Mock
|
@Mock
|
||||||
@@ -113,9 +70,9 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
@Mock
|
@Mock
|
||||||
private VolumeControlProfile mVolumeControlProfile;
|
private VolumeControlProfile mVolumeControlProfile;
|
||||||
@Mock
|
@Mock
|
||||||
private AmbientVolumeController mVolumeController;
|
|
||||||
@Mock
|
|
||||||
private Handler mTestHandler;
|
private Handler mTestHandler;
|
||||||
|
@Mock
|
||||||
|
private AmbientVolumeUiController mUiController;
|
||||||
|
|
||||||
private BluetoothDetailsAmbientVolumePreferenceController mController;
|
private BluetoothDetailsAmbientVolumePreferenceController mController;
|
||||||
|
|
||||||
@@ -124,24 +81,16 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
super.setUp();
|
super.setUp();
|
||||||
|
|
||||||
mContext = spy(mContext);
|
mContext = spy(mContext);
|
||||||
|
|
||||||
|
when(mBluetoothManager.getProfileManager()).thenReturn(mProfileManager);
|
||||||
|
when(mBluetoothManager.getEventManager()).thenReturn(mEventManager);
|
||||||
|
mController = spy(
|
||||||
|
new BluetoothDetailsAmbientVolumePreferenceController(mContext, mBluetoothManager,
|
||||||
|
mFragment, mCachedDevice, mLifecycle, mUiController));
|
||||||
|
|
||||||
PreferenceCategory deviceControls = new PreferenceCategory(mContext);
|
PreferenceCategory deviceControls = new PreferenceCategory(mContext);
|
||||||
deviceControls.setKey(KEY_HEARING_DEVICE_GROUP);
|
deviceControls.setKey(KEY_HEARING_DEVICE_GROUP);
|
||||||
mScreen.addPreference(deviceControls);
|
mScreen.addPreference(deviceControls);
|
||||||
mController = spy(
|
|
||||||
new BluetoothDetailsAmbientVolumePreferenceController(mContext, mBluetoothManager,
|
|
||||||
mFragment, mCachedDevice, mLifecycle, mLocalDataManager,
|
|
||||||
mVolumeController));
|
|
||||||
|
|
||||||
when(mBluetoothManager.getEventManager()).thenReturn(mEventManager);
|
|
||||||
when(mBluetoothManager.getProfileManager()).thenReturn(mProfileManager);
|
|
||||||
when(mProfileManager.getVolumeControlProfile()).thenReturn(mVolumeControlProfile);
|
|
||||||
when(mVolumeControlProfile.getConnectionStatus(mDevice)).thenReturn(
|
|
||||||
BluetoothProfile.STATE_CONNECTED);
|
|
||||||
when(mVolumeControlProfile.getConnectionStatus(mMemberDevice)).thenReturn(
|
|
||||||
BluetoothProfile.STATE_CONNECTED);
|
|
||||||
when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile));
|
|
||||||
when(mLocalDataManager.get(any(BluetoothDevice.class))).thenReturn(
|
|
||||||
new HearingDeviceLocalDataManager.Data.Builder().build());
|
|
||||||
|
|
||||||
when(mContext.getMainThreadHandler()).thenReturn(mTestHandler);
|
when(mContext.getMainThreadHandler()).thenReturn(mTestHandler);
|
||||||
when(mTestHandler.postDelayed(any(Runnable.class), anyLong())).thenAnswer(
|
when(mTestHandler.postDelayed(any(Runnable.class), anyLong())).thenAnswer(
|
||||||
@@ -152,283 +101,42 @@ public class BluetoothDetailsAmbientVolumePreferenceControllerTest extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void init_deviceWithoutMember_controlNotExpandable() {
|
public void init_preferenceAdded() {
|
||||||
prepareDevice(/* hasMember= */ false);
|
|
||||||
|
|
||||||
mController.init(mScreen);
|
mController.init(mScreen);
|
||||||
|
|
||||||
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
||||||
assertThat(preference).isNotNull();
|
assertThat(preference).isNotNull();
|
||||||
assertThat(preference.isExpandable()).isFalse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void init_deviceWithMember_controlExpandable() {
|
public void refresh_deviceNotSupportVcp_verifyUiControllerNoRefresh() {
|
||||||
prepareDevice(/* hasMember= */ true);
|
when(mCachedDevice.getProfiles()).thenReturn(List.of());
|
||||||
|
|
||||||
mController.init(mScreen);
|
mController.refresh();
|
||||||
|
|
||||||
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
verify(mUiController, never()).refresh();
|
||||||
assertThat(preference).isNotNull();
|
|
||||||
assertThat(preference.isExpandable()).isTrue();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onDeviceLocalDataChange_noMemberAndExpanded_uiCorrectAndDataUpdated() {
|
public void refresh_deviceSupportVcp_verifyUiControllerRefresh() {
|
||||||
prepareDevice(/* hasMember= */ false);
|
when(mCachedDevice.getProfiles()).thenReturn(List.of(mVolumeControlProfile));
|
||||||
mController.init(mScreen);
|
|
||||||
HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder()
|
|
||||||
.ambient(0).groupAmbient(0).ambientControlExpanded(true).build();
|
|
||||||
when(mLocalDataManager.get(mDevice)).thenReturn(data);
|
|
||||||
|
|
||||||
mController.onDeviceLocalDataChange(TEST_ADDRESS, data);
|
mController.refresh();
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
|
||||||
|
|
||||||
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
verify(mUiController).refresh();
|
||||||
assertThat(preference).isNotNull();
|
|
||||||
assertThat(preference.isExpanded()).isFalse();
|
|
||||||
verifyDeviceDataUpdated(mDevice);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onDeviceLocalDataChange_noMemberAndCollapsed_uiCorrectAndDataUpdated() {
|
public void onStart_verifyUiControllerStart() {
|
||||||
prepareDevice(/* hasMember= */ false);
|
|
||||||
mController.init(mScreen);
|
|
||||||
HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder()
|
|
||||||
.ambient(0).groupAmbient(0).ambientControlExpanded(false).build();
|
|
||||||
when(mLocalDataManager.get(mDevice)).thenReturn(data);
|
|
||||||
|
|
||||||
mController.onDeviceLocalDataChange(TEST_ADDRESS, data);
|
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
|
||||||
|
|
||||||
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
|
||||||
assertThat(preference).isNotNull();
|
|
||||||
assertThat(preference.isExpanded()).isFalse();
|
|
||||||
verifyDeviceDataUpdated(mDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onDeviceLocalDataChange_hasMemberAndExpanded_uiCorrectAndDataUpdated() {
|
|
||||||
prepareDevice(/* hasMember= */ true);
|
|
||||||
mController.init(mScreen);
|
|
||||||
HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder()
|
|
||||||
.ambient(0).groupAmbient(0).ambientControlExpanded(true).build();
|
|
||||||
when(mLocalDataManager.get(mDevice)).thenReturn(data);
|
|
||||||
|
|
||||||
mController.onDeviceLocalDataChange(TEST_ADDRESS, data);
|
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
|
||||||
|
|
||||||
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
|
||||||
assertThat(preference).isNotNull();
|
|
||||||
assertThat(preference.isExpanded()).isTrue();
|
|
||||||
verifyDeviceDataUpdated(mDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onDeviceLocalDataChange_hasMemberAndCollapsed_uiCorrectAndDataUpdated() {
|
|
||||||
prepareDevice(/* hasMember= */ true);
|
|
||||||
mController.init(mScreen);
|
|
||||||
HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder()
|
|
||||||
.ambient(0).groupAmbient(0).ambientControlExpanded(false).build();
|
|
||||||
when(mLocalDataManager.get(mDevice)).thenReturn(data);
|
|
||||||
|
|
||||||
mController.onDeviceLocalDataChange(TEST_ADDRESS, data);
|
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
|
||||||
|
|
||||||
AmbientVolumePreference preference = mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
|
||||||
assertThat(preference).isNotNull();
|
|
||||||
assertThat(preference.isExpanded()).isFalse();
|
|
||||||
verifyDeviceDataUpdated(mDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onStart_localDataManagerStartAndCallbackRegistered() {
|
|
||||||
prepareDevice(/* hasMember= */ true);
|
|
||||||
mController.init(mScreen);
|
|
||||||
|
|
||||||
mController.onStart();
|
mController.onStart();
|
||||||
|
|
||||||
verify(mLocalDataManager, atLeastOnce()).start();
|
verify(mUiController).start();
|
||||||
verify(mVolumeController).registerCallback(any(Executor.class), eq(mDevice));
|
|
||||||
verify(mVolumeController).registerCallback(any(Executor.class), eq(mMemberDevice));
|
|
||||||
verify(mCachedDevice).registerCallback(any(Executor.class),
|
|
||||||
any(CachedBluetoothDevice.Callback.class));
|
|
||||||
verify(mCachedMemberDevice).registerCallback(any(Executor.class),
|
|
||||||
any(CachedBluetoothDevice.Callback.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onStop_localDataManagerStopAndCallbackUnregistered() {
|
public void onStop_verifyUiControllerStop() {
|
||||||
prepareDevice(/* hasMember= */ true);
|
|
||||||
mController.init(mScreen);
|
|
||||||
|
|
||||||
mController.onStop();
|
mController.onStop();
|
||||||
|
|
||||||
verify(mLocalDataManager).stop();
|
verify(mUiController).stop();
|
||||||
verify(mVolumeController).unregisterCallback(mDevice);
|
|
||||||
verify(mVolumeController).unregisterCallback(mMemberDevice);
|
|
||||||
verify(mCachedDevice).unregisterCallback(any(CachedBluetoothDevice.Callback.class));
|
|
||||||
verify(mCachedMemberDevice).unregisterCallback(any(CachedBluetoothDevice.Callback.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onDeviceAttributesChanged_newDevice_newPreference() {
|
|
||||||
prepareDevice(/* hasMember= */ false);
|
|
||||||
mController.init(mScreen);
|
|
||||||
|
|
||||||
// check the right control is null before onDeviceAttributesChanged()
|
|
||||||
SeekBarPreference leftControl = mScreen.findPreference(LEFT_CONTROL_KEY);
|
|
||||||
SeekBarPreference rightControl = mScreen.findPreference(RIGHT_CONTROL_KEY);
|
|
||||||
assertThat(leftControl).isNotNull();
|
|
||||||
assertThat(rightControl).isNull();
|
|
||||||
|
|
||||||
prepareDevice(/* hasMember= */ true);
|
|
||||||
mController.onDeviceAttributesChanged();
|
|
||||||
shadowOf(Looper.getMainLooper()).idle();
|
|
||||||
|
|
||||||
// check the right control is created after onDeviceAttributesChanged()
|
|
||||||
SeekBarPreference updatedLeftControl = mScreen.findPreference(LEFT_CONTROL_KEY);
|
|
||||||
SeekBarPreference updatedRightControl = mScreen.findPreference(RIGHT_CONTROL_KEY);
|
|
||||||
assertThat(updatedLeftControl).isEqualTo(leftControl);
|
|
||||||
assertThat(updatedRightControl).isNotNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onAmbientChanged_refreshWhenNotInitiateFromUi() {
|
|
||||||
prepareDevice(/* hasMember= */ false);
|
|
||||||
mController.init(mScreen);
|
|
||||||
final int testAmbient = 10;
|
|
||||||
HearingDeviceLocalDataManager.Data data = new HearingDeviceLocalDataManager.Data.Builder()
|
|
||||||
.ambient(testAmbient)
|
|
||||||
.groupAmbient(testAmbient)
|
|
||||||
.ambientControlExpanded(false)
|
|
||||||
.build();
|
|
||||||
when(mLocalDataManager.get(mDevice)).thenReturn(data);
|
|
||||||
getPreference().setExpanded(true);
|
|
||||||
|
|
||||||
mController.onAmbientChanged(mDevice, testAmbient);
|
|
||||||
verify(mController, never()).refresh();
|
|
||||||
|
|
||||||
final int updatedTestAmbient = 20;
|
|
||||||
mController.onAmbientChanged(mDevice, updatedTestAmbient);
|
|
||||||
verify(mController).refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onMuteChanged_refreshWhenNotInitiateFromUi() {
|
|
||||||
prepareDevice(/* hasMember= */ false);
|
|
||||||
mController.init(mScreen);
|
|
||||||
final int testMute = MUTE_NOT_MUTED;
|
|
||||||
AmbientVolumeController.RemoteAmbientState state =
|
|
||||||
new AmbientVolumeController.RemoteAmbientState(testMute, 0);
|
|
||||||
when(mVolumeController.refreshAmbientState(mDevice)).thenReturn(state);
|
|
||||||
getPreference().setMuted(false);
|
|
||||||
|
|
||||||
mController.onMuteChanged(mDevice, testMute);
|
|
||||||
verify(mController, never()).refresh();
|
|
||||||
|
|
||||||
final int updatedTestMute = MUTE_MUTED;
|
|
||||||
mController.onMuteChanged(mDevice, updatedTestMute);
|
|
||||||
verify(mController).refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void refresh_leftAndRightDifferentGainSetting_expandControl() {
|
|
||||||
prepareDevice(/* hasMember= */ true);
|
|
||||||
mController.init(mScreen);
|
|
||||||
prepareRemoteData(mDevice, 10, MUTE_NOT_MUTED);
|
|
||||||
prepareRemoteData(mMemberDevice, 20, MUTE_NOT_MUTED);
|
|
||||||
getPreference().setExpanded(false);
|
|
||||||
|
|
||||||
mController.refresh();
|
|
||||||
|
|
||||||
assertThat(getPreference().isExpanded()).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void refresh_oneSideNotMutable_controlNotMutableAndNotMuted() {
|
|
||||||
prepareDevice(/* hasMember= */ true);
|
|
||||||
mController.init(mScreen);
|
|
||||||
prepareRemoteData(mDevice, 10, MUTE_DISABLED);
|
|
||||||
prepareRemoteData(mMemberDevice, 20, MUTE_NOT_MUTED);
|
|
||||||
getPreference().setMutable(true);
|
|
||||||
getPreference().setMuted(true);
|
|
||||||
|
|
||||||
mController.refresh();
|
|
||||||
|
|
||||||
assertThat(getPreference().isMutable()).isFalse();
|
|
||||||
assertThat(getPreference().isMuted()).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void refresh_oneSideNotMuted_controlNotMutedAndSyncToRemote() {
|
|
||||||
prepareDevice(/* hasMember= */ true);
|
|
||||||
mController.init(mScreen);
|
|
||||||
prepareRemoteData(mDevice, 10, MUTE_MUTED);
|
|
||||||
prepareRemoteData(mMemberDevice, 20, MUTE_NOT_MUTED);
|
|
||||||
getPreference().setMutable(true);
|
|
||||||
getPreference().setMuted(true);
|
|
||||||
|
|
||||||
mController.refresh();
|
|
||||||
|
|
||||||
assertThat(getPreference().isMutable()).isTrue();
|
|
||||||
assertThat(getPreference().isMuted()).isFalse();
|
|
||||||
verify(mVolumeController).setMuted(mDevice, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prepareDevice(boolean hasMember) {
|
|
||||||
when(mCachedDevice.getDeviceSide()).thenReturn(SIDE_LEFT);
|
|
||||||
when(mCachedDevice.getDevice()).thenReturn(mDevice);
|
|
||||||
when(mCachedDevice.getBondState()).thenReturn(BOND_BONDED);
|
|
||||||
when(mDevice.getAddress()).thenReturn(TEST_ADDRESS);
|
|
||||||
when(mDevice.getAnonymizedAddress()).thenReturn(TEST_ADDRESS);
|
|
||||||
when(mDevice.isConnected()).thenReturn(true);
|
|
||||||
if (hasMember) {
|
|
||||||
when(mCachedDevice.getMemberDevice()).thenReturn(Set.of(mCachedMemberDevice));
|
|
||||||
when(mCachedMemberDevice.getDeviceSide()).thenReturn(SIDE_RIGHT);
|
|
||||||
when(mCachedMemberDevice.getDevice()).thenReturn(mMemberDevice);
|
|
||||||
when(mCachedMemberDevice.getBondState()).thenReturn(BOND_BONDED);
|
|
||||||
when(mMemberDevice.getAddress()).thenReturn(TEST_MEMBER_ADDRESS);
|
|
||||||
when(mMemberDevice.getAnonymizedAddress()).thenReturn(TEST_MEMBER_ADDRESS);
|
|
||||||
when(mMemberDevice.isConnected()).thenReturn(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prepareRemoteData(BluetoothDevice device, int gainSetting, int mute) {
|
|
||||||
when(mVolumeController.isAmbientControlAvailable(device)).thenReturn(true);
|
|
||||||
when(mVolumeController.refreshAmbientState(device)).thenReturn(
|
|
||||||
new AmbientVolumeController.RemoteAmbientState(gainSetting, mute));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void verifyDeviceDataUpdated(BluetoothDevice device) {
|
|
||||||
verify(mLocalDataManager, atLeastOnce()).updateAmbient(eq(device), anyInt());
|
|
||||||
verify(mLocalDataManager, atLeastOnce()).updateGroupAmbient(eq(device), anyInt());
|
|
||||||
verify(mLocalDataManager, atLeastOnce()).updateAmbientControlExpanded(eq(device),
|
|
||||||
anyBoolean());
|
|
||||||
}
|
|
||||||
|
|
||||||
private AmbientVolumePreference getPreference() {
|
|
||||||
return mScreen.findPreference(KEY_AMBIENT_VOLUME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Implements(value = Settings.Global.class)
|
|
||||||
public static class ShadowGlobal extends ShadowSettings.ShadowGlobal {
|
|
||||||
private static final Map<ContentResolver, Map<String, String>> sDataMap = new HashMap<>();
|
|
||||||
|
|
||||||
@Implementation
|
|
||||||
protected static boolean putStringForUser(
|
|
||||||
ContentResolver cr, String name, String value, int userHandle) {
|
|
||||||
get(cr).put(name, value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Implementation
|
|
||||||
protected static String getStringForUser(ContentResolver cr, String name, int userHandle) {
|
|
||||||
return get(cr).get(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Map<String, String> get(ContentResolver cr) {
|
|
||||||
return sDataMap.computeIfAbsent(cr, k -> new HashMap<>());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,14 @@ import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
|
|||||||
import static android.security.advancedprotection.AdvancedProtectionManager.ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG;
|
import static android.security.advancedprotection.AdvancedProtectionManager.ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG;
|
||||||
import static android.security.advancedprotection.AdvancedProtectionManager.ADVANCED_PROTECTION_SYSTEM_ENTITY;
|
import static android.security.advancedprotection.AdvancedProtectionManager.ADVANCED_PROTECTION_SYSTEM_ENTITY;
|
||||||
import static android.security.advancedprotection.AdvancedProtectionManager.EXTRA_SUPPORT_DIALOG_FEATURE;
|
import static android.security.advancedprotection.AdvancedProtectionManager.EXTRA_SUPPORT_DIALOG_FEATURE;
|
||||||
|
import static android.security.advancedprotection.AdvancedProtectionManager.EXTRA_SUPPORT_DIALOG_TYPE;
|
||||||
|
import static android.security.advancedprotection.AdvancedProtectionManager.FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES;
|
||||||
|
import static android.security.advancedprotection.AdvancedProtectionManager.SUPPORT_DIALOG_TYPE_UNKNOWN;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
@@ -40,7 +45,6 @@ import android.os.UserManager;
|
|||||||
import android.platform.test.annotations.RequiresFlagsEnabled;
|
import android.platform.test.annotations.RequiresFlagsEnabled;
|
||||||
import android.platform.test.flag.junit.CheckFlagsRule;
|
import android.platform.test.flag.junit.CheckFlagsRule;
|
||||||
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
|
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
|
||||||
import android.security.advancedprotection.AdvancedProtectionManager;
|
|
||||||
|
|
||||||
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||||
|
|
||||||
@@ -48,6 +52,7 @@ import org.junit.Before;
|
|||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
@@ -59,8 +64,6 @@ public class ActionDisabledByAdminDialogTest {
|
|||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private DevicePolicyManager mDevicePolicyManager;
|
private DevicePolicyManager mDevicePolicyManager;
|
||||||
@Mock
|
|
||||||
private AdvancedProtectionManager mAdvancedProtectionManager;
|
|
||||||
|
|
||||||
private ActionDisabledByAdminDialog mDialog;
|
private ActionDisabledByAdminDialog mDialog;
|
||||||
private final ComponentName mAdminComponent = new ComponentName("admin", "adminclass");
|
private final ComponentName mAdminComponent = new ComponentName("admin", "adminclass");
|
||||||
@@ -70,8 +73,6 @@ public class ActionDisabledByAdminDialogTest {
|
|||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
mDialog = spy(new ActionDisabledByAdminDialog());
|
mDialog = spy(new ActionDisabledByAdminDialog());
|
||||||
doReturn(mDevicePolicyManager).when(mDialog).getSystemService(DevicePolicyManager.class);
|
doReturn(mDevicePolicyManager).when(mDialog).getSystemService(DevicePolicyManager.class);
|
||||||
doReturn(mAdvancedProtectionManager).when(mDialog).getSystemService(
|
|
||||||
AdvancedProtectionManager.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -118,24 +119,28 @@ public class ActionDisabledByAdminDialogTest {
|
|||||||
advancedProtectionAuthority, UserHandle.of(userId), mAdminComponent);
|
advancedProtectionAuthority, UserHandle.of(userId), mAdminComponent);
|
||||||
final String userRestriction = UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY;
|
final String userRestriction = UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY;
|
||||||
|
|
||||||
final Intent apmIntent = new Intent(ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG);
|
|
||||||
apmIntent.setFlags(FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
apmIntent.putExtra(EXTRA_SUPPORT_DIALOG_FEATURE, "featureId");
|
|
||||||
|
|
||||||
final Intent dialogIntent = new Intent();
|
final Intent dialogIntent = new Intent();
|
||||||
dialogIntent.putExtra(Intent.EXTRA_USER_ID, userId);
|
dialogIntent.putExtra(Intent.EXTRA_USER_ID, userId);
|
||||||
dialogIntent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, userRestriction);
|
dialogIntent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, userRestriction);
|
||||||
|
|
||||||
when(mDevicePolicyManager.getEnforcingAdmin(userId, userRestriction))
|
when(mDevicePolicyManager.getEnforcingAdmin(userId, userRestriction))
|
||||||
.thenReturn(advancedProtectionEnforcingAdmin);
|
.thenReturn(advancedProtectionEnforcingAdmin);
|
||||||
when(mAdvancedProtectionManager.createSupportIntentForPolicyIdentifierOrRestriction(
|
doNothing().when(mDialog).startActivityAsUser(any(), eq(UserHandle.of(userId)));
|
||||||
userRestriction, /* type */ null)).thenReturn(apmIntent);
|
|
||||||
doNothing().when(mDialog).startActivityAsUser(apmIntent, UserHandle.of(userId));
|
|
||||||
|
|
||||||
mDialog.getAdminDetailsFromIntent(dialogIntent);
|
mDialog.getAdminDetailsFromIntent(dialogIntent);
|
||||||
|
|
||||||
verify(mDialog).startActivityAsUser(apmIntent, UserHandle.of(userId));
|
ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||||
|
verify(mDialog).startActivityAsUser(intentCaptor.capture(), eq(UserHandle.of(userId)));
|
||||||
assertTrue(mDialog.isFinishing());
|
assertTrue(mDialog.isFinishing());
|
||||||
|
|
||||||
|
Intent launchedIntent = intentCaptor.getValue();
|
||||||
|
assertEquals("Intent action is incorrect", ACTION_SHOW_ADVANCED_PROTECTION_SUPPORT_DIALOG,
|
||||||
|
launchedIntent.getAction());
|
||||||
|
assertEquals("Feature ID extra is incorrect", FEATURE_ID_DISALLOW_INSTALL_UNKNOWN_SOURCES,
|
||||||
|
launchedIntent.getIntExtra(EXTRA_SUPPORT_DIALOG_FEATURE, -1));
|
||||||
|
assertEquals("Type is incorrect", SUPPORT_DIALOG_TYPE_UNKNOWN,
|
||||||
|
launchedIntent.getIntExtra(EXTRA_SUPPORT_DIALOG_TYPE, -1));
|
||||||
|
assertEquals(FLAG_ACTIVITY_NEW_TASK, launchedIntent.getFlags());
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API)
|
@RequiresFlagsEnabled(android.security.Flags.FLAG_AAPM_API)
|
||||||
|
|||||||
@@ -41,10 +41,8 @@ import com.android.settingslib.graph.preferenceGroupProto
|
|||||||
import com.android.settingslib.graph.preferenceOrGroupProto
|
import com.android.settingslib.graph.preferenceOrGroupProto
|
||||||
import com.android.settingslib.graph.preferenceProto
|
import com.android.settingslib.graph.preferenceProto
|
||||||
import com.android.settingslib.graph.preferenceScreenProto
|
import com.android.settingslib.graph.preferenceScreenProto
|
||||||
|
import com.android.settingslib.graph.preferenceValueProto
|
||||||
import com.android.settingslib.graph.proto.PreferenceGraphProto
|
import com.android.settingslib.graph.proto.PreferenceGraphProto
|
||||||
import com.android.settingslib.graph.proto.PreferenceProto
|
|
||||||
import com.android.settingslib.graph.proto.PreferenceValueProto
|
|
||||||
import com.android.settingslib.graph.proto.TextProto
|
|
||||||
import com.android.settingslib.graph.textProto
|
import com.android.settingslib.graph.textProto
|
||||||
import com.android.settingslib.graph.toProto
|
import com.android.settingslib.graph.toProto
|
||||||
import com.android.settingslib.metadata.SensitivityLevel
|
import com.android.settingslib.metadata.SensitivityLevel
|
||||||
@@ -57,8 +55,7 @@ import org.junit.runner.RunWith
|
|||||||
@RequiresFlagsEnabled(FLAG_SETTINGS_CATALYST)
|
@RequiresFlagsEnabled(FLAG_SETTINGS_CATALYST)
|
||||||
class PreferenceServiceRequestTransformerTest {
|
class PreferenceServiceRequestTransformerTest {
|
||||||
|
|
||||||
@get:Rule
|
@get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
|
||||||
val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun transformCatalystGetMetadataResponse_emptyGraph_returnsFrameworkResponseWithError() {
|
fun transformCatalystGetMetadataResponse_emptyGraph_returnsFrameworkResponseWithError() {
|
||||||
@@ -97,7 +94,7 @@ class PreferenceServiceRequestTransformerTest {
|
|||||||
title = textProto { string = "title2" }
|
title = textProto { string = "title2" }
|
||||||
enabled = false
|
enabled = false
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -110,21 +107,23 @@ class PreferenceServiceRequestTransformerTest {
|
|||||||
assertThat(metadataList.size).isEqualTo(2)
|
assertThat(metadataList.size).isEqualTo(2)
|
||||||
}
|
}
|
||||||
assertThat(
|
assertThat(
|
||||||
fResult.metadataList.any {
|
fResult.metadataList.any {
|
||||||
it.key == "key1" &&
|
it.key == "key1" &&
|
||||||
it.screenKey == "screen" &&
|
it.screenKey == "screen" &&
|
||||||
it.title == "title1" &&
|
it.title == "title1" &&
|
||||||
it.isEnabled == true
|
it.isEnabled
|
||||||
}
|
}
|
||||||
).isTrue()
|
)
|
||||||
|
.isTrue()
|
||||||
assertThat(
|
assertThat(
|
||||||
fResult.metadataList.any {
|
fResult.metadataList.any {
|
||||||
it.key == "key2" &&
|
it.key == "key2" &&
|
||||||
it.screenKey == "screen" &&
|
it.screenKey == "screen" &&
|
||||||
it.title == "title2" &&
|
it.title == "title2" &&
|
||||||
it.isEnabled == false
|
!it.isEnabled
|
||||||
}
|
}
|
||||||
).isTrue()
|
)
|
||||||
|
.isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -143,26 +142,28 @@ class PreferenceServiceRequestTransformerTest {
|
|||||||
fun transformCatalystGetValueResponse_success_returnsValidFrameworkResponse() {
|
fun transformCatalystGetValueResponse_success_returnsValidFrameworkResponse() {
|
||||||
val context: Context = ApplicationProvider.getApplicationContext()
|
val context: Context = ApplicationProvider.getApplicationContext()
|
||||||
val fRequest = GetValueRequest.Builder("screen", "key").build()
|
val fRequest = GetValueRequest.Builder("screen", "key").build()
|
||||||
val cResult = PreferenceGetterResponse(
|
val cResult =
|
||||||
emptyMap(),
|
PreferenceGetterResponse(
|
||||||
mapOf(
|
emptyMap(),
|
||||||
PreferenceCoordinate(fRequest.screenKey, fRequest.preferenceKey) to
|
mapOf(
|
||||||
PreferenceProto.newBuilder()
|
PreferenceCoordinate(fRequest.screenKey, fRequest.preferenceKey) to
|
||||||
.setKey("key")
|
preferenceProto {
|
||||||
.setTitle(TextProto.newBuilder().setString("title"))
|
key = "key"
|
||||||
.setSummary(TextProto.newBuilder().setString("summary"))
|
title = textProto { string = "title" }
|
||||||
.setEnabled(true)
|
summary = textProto { string = "summary" }
|
||||||
.setAvailable(true)
|
enabled = true
|
||||||
.setRestricted(true)
|
available = true
|
||||||
.setPersistent(true)
|
restricted = true
|
||||||
.setSensitivityLevel(SensitivityLevel.LOW_SENSITIVITY)
|
persistent = true
|
||||||
.setLaunchIntent(
|
sensitivityLevel = SensitivityLevel.LOW_SENSITIVITY
|
||||||
|
addReadPermissions("read_permission")
|
||||||
|
addWritePermissions("write_permission")
|
||||||
|
launchIntent =
|
||||||
Intent(context, SettingsHomepageActivity::class.java).toProto()
|
Intent(context, SettingsHomepageActivity::class.java).toProto()
|
||||||
)
|
value = preferenceValueProto { booleanValue = true }
|
||||||
.setValue(PreferenceValueProto.newBuilder().setBooleanValue(true))
|
}
|
||||||
.build()
|
),
|
||||||
)
|
)
|
||||||
)
|
|
||||||
val fResult = transformCatalystGetValueResponse(context, fRequest, cResult)
|
val fResult = transformCatalystGetValueResponse(context, fRequest, cResult)
|
||||||
assertThat(fResult!!.resultCode).isEqualTo(GetValueResult.RESULT_OK)
|
assertThat(fResult!!.resultCode).isEqualTo(GetValueResult.RESULT_OK)
|
||||||
with(fResult.metadata!!) {
|
with(fResult.metadata!!) {
|
||||||
@@ -174,6 +175,8 @@ class PreferenceServiceRequestTransformerTest {
|
|||||||
assertThat(isWritable).isTrue()
|
assertThat(isWritable).isTrue()
|
||||||
assertThat(writeSensitivity)
|
assertThat(writeSensitivity)
|
||||||
.isEqualTo(SettingsPreferenceMetadata.EXPECT_POST_CONFIRMATION)
|
.isEqualTo(SettingsPreferenceMetadata.EXPECT_POST_CONFIRMATION)
|
||||||
|
assertThat(readPermissions).containsExactly("read_permission")
|
||||||
|
assertThat(writePermissions).containsExactly("write_permission")
|
||||||
assertThat(launchIntent).isNotNull()
|
assertThat(launchIntent).isNotNull()
|
||||||
assertThat(launchIntent!!.component!!.className)
|
assertThat(launchIntent!!.component!!.className)
|
||||||
.isEqualTo(SettingsHomepageActivity::class.java.name)
|
.isEqualTo(SettingsHomepageActivity::class.java.name)
|
||||||
@@ -188,13 +191,14 @@ class PreferenceServiceRequestTransformerTest {
|
|||||||
fun transformCatalystGetValueResponse_failure_returnsValidFrameworkResponse() {
|
fun transformCatalystGetValueResponse_failure_returnsValidFrameworkResponse() {
|
||||||
val context: Context = ApplicationProvider.getApplicationContext()
|
val context: Context = ApplicationProvider.getApplicationContext()
|
||||||
val fRequest = GetValueRequest.Builder("screen", "key").build()
|
val fRequest = GetValueRequest.Builder("screen", "key").build()
|
||||||
val cResult = PreferenceGetterResponse(
|
val cResult =
|
||||||
mapOf(
|
PreferenceGetterResponse(
|
||||||
PreferenceCoordinate(fRequest.screenKey, fRequest.preferenceKey) to
|
mapOf(
|
||||||
|
PreferenceCoordinate(fRequest.screenKey, fRequest.preferenceKey) to
|
||||||
PreferenceGetterErrorCode.NOT_FOUND
|
PreferenceGetterErrorCode.NOT_FOUND
|
||||||
),
|
),
|
||||||
emptyMap()
|
emptyMap(),
|
||||||
)
|
)
|
||||||
val fResult = transformCatalystGetValueResponse(context, fRequest, cResult)
|
val fResult = transformCatalystGetValueResponse(context, fRequest, cResult)
|
||||||
with(fResult!!) {
|
with(fResult!!) {
|
||||||
assertThat(resultCode).isEqualTo(GetValueResult.RESULT_UNSUPPORTED)
|
assertThat(resultCode).isEqualTo(GetValueResult.RESULT_UNSUPPORTED)
|
||||||
@@ -214,13 +218,15 @@ class PreferenceServiceRequestTransformerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun transformFrameworkSetValueRequest_typeBoolean_returnsValidCatalystRequest() {
|
fun transformFrameworkSetValueRequest_typeBoolean_returnsValidCatalystRequest() {
|
||||||
val fRequest = SetValueRequest.Builder(
|
val fRequest =
|
||||||
"screen",
|
SetValueRequest.Builder(
|
||||||
"pref",
|
"screen",
|
||||||
SettingsPreferenceValue.Builder(SettingsPreferenceValue.TYPE_BOOLEAN)
|
"pref",
|
||||||
.setBooleanValue(true)
|
SettingsPreferenceValue.Builder(SettingsPreferenceValue.TYPE_BOOLEAN)
|
||||||
|
.setBooleanValue(true)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
).build()
|
|
||||||
val cRequest = transformFrameworkSetValueRequest(fRequest)
|
val cRequest = transformFrameworkSetValueRequest(fRequest)
|
||||||
with(cRequest!!) {
|
with(cRequest!!) {
|
||||||
assertThat(screenKey).isEqualTo(fRequest.screenKey)
|
assertThat(screenKey).isEqualTo(fRequest.screenKey)
|
||||||
@@ -232,13 +238,15 @@ class PreferenceServiceRequestTransformerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun transformFrameworkSetValueRequest_typeInt_returnsValidCatalystRequest() {
|
fun transformFrameworkSetValueRequest_typeInt_returnsValidCatalystRequest() {
|
||||||
val fRequest = SetValueRequest.Builder(
|
val fRequest =
|
||||||
"screen",
|
SetValueRequest.Builder(
|
||||||
"pref",
|
"screen",
|
||||||
SettingsPreferenceValue.Builder(SettingsPreferenceValue.TYPE_INT)
|
"pref",
|
||||||
.setIntValue(5)
|
SettingsPreferenceValue.Builder(SettingsPreferenceValue.TYPE_INT)
|
||||||
|
.setIntValue(5)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
).build()
|
|
||||||
val cRequest = transformFrameworkSetValueRequest(fRequest)
|
val cRequest = transformFrameworkSetValueRequest(fRequest)
|
||||||
with(cRequest!!) {
|
with(cRequest!!) {
|
||||||
assertThat(screenKey).isEqualTo(fRequest.screenKey)
|
assertThat(screenKey).isEqualTo(fRequest.screenKey)
|
||||||
@@ -250,59 +258,59 @@ class PreferenceServiceRequestTransformerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun transformFrameworkSetValueRequest_typeString_returnsNull() {
|
fun transformFrameworkSetValueRequest_typeString_returnsNull() {
|
||||||
val fRequest = SetValueRequest.Builder(
|
val fRequest =
|
||||||
"screen",
|
SetValueRequest.Builder(
|
||||||
"pref",
|
"screen",
|
||||||
SettingsPreferenceValue.Builder(SettingsPreferenceValue.TYPE_STRING)
|
"pref",
|
||||||
.setStringValue("value")
|
SettingsPreferenceValue.Builder(SettingsPreferenceValue.TYPE_STRING)
|
||||||
|
.setStringValue("value")
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
).build()
|
|
||||||
val cRequest = transformFrameworkSetValueRequest(fRequest)
|
val cRequest = transformFrameworkSetValueRequest(fRequest)
|
||||||
assertThat(cRequest).isNull()
|
assertThat(cRequest).isNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun transformCatalystSetValueResponse_returnsValidFrameworkResponse() {
|
fun transformCatalystSetValueResponse_returnsValidFrameworkResponse() {
|
||||||
assertThat(
|
assertThat(transformCatalystSetValueResponse(PreferenceSetterResult.OK).resultCode)
|
||||||
transformCatalystSetValueResponse(PreferenceSetterResult.OK).resultCode
|
.isEqualTo(SetValueResult.RESULT_OK)
|
||||||
).isEqualTo(SetValueResult.RESULT_OK)
|
|
||||||
|
assertThat(transformCatalystSetValueResponse(PreferenceSetterResult.UNAVAILABLE).resultCode)
|
||||||
|
.isEqualTo(SetValueResult.RESULT_UNAVAILABLE)
|
||||||
|
|
||||||
|
assertThat(transformCatalystSetValueResponse(PreferenceSetterResult.DISABLED).resultCode)
|
||||||
|
.isEqualTo(SetValueResult.RESULT_DISABLED)
|
||||||
|
|
||||||
|
assertThat(transformCatalystSetValueResponse(PreferenceSetterResult.UNSUPPORTED).resultCode)
|
||||||
|
.isEqualTo(SetValueResult.RESULT_UNSUPPORTED)
|
||||||
|
|
||||||
|
assertThat(transformCatalystSetValueResponse(PreferenceSetterResult.DISALLOW).resultCode)
|
||||||
|
.isEqualTo(SetValueResult.RESULT_DISALLOW)
|
||||||
|
|
||||||
assertThat(
|
assertThat(
|
||||||
transformCatalystSetValueResponse(PreferenceSetterResult.UNAVAILABLE).resultCode
|
transformCatalystSetValueResponse(PreferenceSetterResult.REQUIRE_APP_PERMISSION)
|
||||||
).isEqualTo(SetValueResult.RESULT_UNAVAILABLE)
|
.resultCode
|
||||||
|
)
|
||||||
|
.isEqualTo(SetValueResult.RESULT_REQUIRE_APP_PERMISSION)
|
||||||
|
|
||||||
assertThat(
|
assertThat(
|
||||||
transformCatalystSetValueResponse(PreferenceSetterResult.DISABLED).resultCode
|
transformCatalystSetValueResponse(PreferenceSetterResult.REQUIRE_USER_AGREEMENT)
|
||||||
).isEqualTo(SetValueResult.RESULT_DISABLED)
|
.resultCode
|
||||||
|
)
|
||||||
|
.isEqualTo(SetValueResult.RESULT_REQUIRE_USER_CONSENT)
|
||||||
|
|
||||||
|
assertThat(transformCatalystSetValueResponse(PreferenceSetterResult.RESTRICTED).resultCode)
|
||||||
|
.isEqualTo(SetValueResult.RESULT_RESTRICTED)
|
||||||
|
|
||||||
assertThat(
|
assertThat(
|
||||||
transformCatalystSetValueResponse(PreferenceSetterResult.UNSUPPORTED).resultCode
|
transformCatalystSetValueResponse(PreferenceSetterResult.INVALID_REQUEST).resultCode
|
||||||
).isEqualTo(SetValueResult.RESULT_UNSUPPORTED)
|
)
|
||||||
|
.isEqualTo(SetValueResult.RESULT_INVALID_REQUEST)
|
||||||
|
|
||||||
assertThat(
|
assertThat(
|
||||||
transformCatalystSetValueResponse(PreferenceSetterResult.DISALLOW).resultCode
|
transformCatalystSetValueResponse(PreferenceSetterResult.INTERNAL_ERROR).resultCode
|
||||||
).isEqualTo(SetValueResult.RESULT_DISALLOW)
|
)
|
||||||
|
.isEqualTo(SetValueResult.RESULT_INTERNAL_ERROR)
|
||||||
assertThat(
|
|
||||||
transformCatalystSetValueResponse(PreferenceSetterResult.REQUIRE_APP_PERMISSION)
|
|
||||||
.resultCode
|
|
||||||
).isEqualTo(SetValueResult.RESULT_REQUIRE_APP_PERMISSION)
|
|
||||||
|
|
||||||
assertThat(
|
|
||||||
transformCatalystSetValueResponse(PreferenceSetterResult.REQUIRE_USER_AGREEMENT)
|
|
||||||
.resultCode
|
|
||||||
).isEqualTo(SetValueResult.RESULT_REQUIRE_USER_CONSENT)
|
|
||||||
|
|
||||||
assertThat(
|
|
||||||
transformCatalystSetValueResponse(PreferenceSetterResult.RESTRICTED).resultCode
|
|
||||||
).isEqualTo(SetValueResult.RESULT_RESTRICTED)
|
|
||||||
|
|
||||||
assertThat(
|
|
||||||
transformCatalystSetValueResponse(PreferenceSetterResult.INVALID_REQUEST).resultCode
|
|
||||||
).isEqualTo(SetValueResult.RESULT_INVALID_REQUEST)
|
|
||||||
|
|
||||||
assertThat(
|
|
||||||
transformCatalystSetValueResponse(PreferenceSetterResult.INTERNAL_ERROR).resultCode
|
|
||||||
).isEqualTo(SetValueResult.RESULT_INTERNAL_ERROR)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,7 +200,6 @@ class WepNetworksPreferenceControllerTest {
|
|||||||
fun whenClick_aapmEnabled_openDialog() {
|
fun whenClick_aapmEnabled_openDialog() {
|
||||||
mockAapmManager.stub {
|
mockAapmManager.stub {
|
||||||
on { isAdvancedProtectionEnabled } doReturn true
|
on { isAdvancedProtectionEnabled } doReturn true
|
||||||
on { createSupportIntent(any(), any()) } doReturn Intent()
|
|
||||||
}
|
}
|
||||||
doNothing().whenever(context).startActivity(any())
|
doNothing().whenever(context).startActivity(any())
|
||||||
composeTestRule.setContent { controller.Content() }
|
composeTestRule.setContent { controller.Content() }
|
||||||
|
|||||||
Reference in New Issue
Block a user