Snap for 8310722 from 9793acfafd to tm-release
Change-Id: I8c950e2f8f59802eb17f2a1f2a2d1786d4a797d1
This commit is contained in:
@@ -1,46 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (C) 2016 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_marginBottom="12dp" >
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="12dp"
|
|
||||||
android:layout_marginEnd="12dp"
|
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:textSize="18sp"
|
|
||||||
android:text="@string/confirm_convert_to_fbe_warning" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
<Button
|
|
||||||
android:id="@+id/button_confirm_convert_fbe"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:text="@string/button_confirm_convert_fbe" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- Copyright (C) 2015 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.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_marginBottom="12dp" >
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="@dimen/preference_no_icon_padding_start"
|
|
||||||
android:layout_marginEnd="12dp"
|
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:textSize="18sp"
|
|
||||||
android:text="@string/convert_to_fbe_warning" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="fill_parent"
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
<Button
|
|
||||||
android:id="@+id/button_convert_fbe"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="bottom"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:text="@string/button_convert_fbe" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
137
res/layout/le_audio_bt_entity_header.xml
Normal file
137
res/layout/le_audio_bt_entity_header.xml
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Copyright (C) 2022 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/entity_header"
|
||||||
|
style="@style/EntityHeader"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerHorizontal="true"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entity_header_title"
|
||||||
|
style="@style/TextAppearance.EntityHeaderTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:singleLine="false"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:textDirection="locale"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/entity_header_summary"
|
||||||
|
style="@style/TextAppearance.EntityHeaderSummary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:singleLine="false"
|
||||||
|
android:ellipsize="marquee"
|
||||||
|
android:textDirection="locale"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/entity_header_icon"
|
||||||
|
android:layout_width="72dp"
|
||||||
|
android:layout_height="72dp"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:antialias="true"/>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/le_bluetooth_battery_start_margin"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bt_battery_case_title"
|
||||||
|
style="@style/TextAppearance.EntityHeaderTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textDirection="locale"
|
||||||
|
android:text="@string/bluetooth_middle_name"
|
||||||
|
android:textSize="@dimen/advanced_bluetooth_header_title_text_size"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bt_battery_left_title"
|
||||||
|
style="@style/TextAppearance.EntityHeaderTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textDirection="locale"
|
||||||
|
android:text="@string/bluetooth_left_name"
|
||||||
|
android:textSize="@dimen/advanced_bluetooth_header_title_text_size"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bt_battery_right_title"
|
||||||
|
style="@style/TextAppearance.EntityHeaderTitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textDirection="locale"
|
||||||
|
android:text="@string/bluetooth_right_name"
|
||||||
|
android:textSize="@dimen/advanced_bluetooth_header_title_text_size"/>
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/le_bluetooth_summary_start_margin"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bt_battery_case_summary"
|
||||||
|
style="@style/TextAppearance.EntityHeaderSummary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
|
||||||
|
android:padding="@dimen/le_bluetooth_summary_padding"
|
||||||
|
android:drawablePadding="@dimen/le_bluetooth_summary_drawable_padding"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bt_battery_left_summary"
|
||||||
|
style="@style/TextAppearance.EntityHeaderSummary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
|
||||||
|
android:padding="@dimen/le_bluetooth_summary_padding"
|
||||||
|
android:drawablePadding="@dimen/le_bluetooth_summary_drawable_padding"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/bt_battery_right_summary"
|
||||||
|
style="@style/TextAppearance.EntityHeaderSummary"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/le_bluetooth_battery_top_margin"
|
||||||
|
android:padding="@dimen/le_bluetooth_summary_padding"
|
||||||
|
android:drawablePadding="@dimen/le_bluetooth_summary_drawable_padding"/>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
0
res/raw/udfps_right_edge_hint_lottie.json
Normal file
0
res/raw/udfps_right_edge_hint_lottie.json
Normal file
@@ -399,6 +399,13 @@
|
|||||||
<dimen name="advanced_bluetooth_battery_height">27.5dp</dimen>
|
<dimen name="advanced_bluetooth_battery_height">27.5dp</dimen>
|
||||||
<dimen name="advanced_bluetooth_battery_right_margin">-4dp</dimen>
|
<dimen name="advanced_bluetooth_battery_right_margin">-4dp</dimen>
|
||||||
|
|
||||||
|
<!-- Header layout of LE audio bluetooth device at bluretooth device detalis -->
|
||||||
|
<dimen name="le_bluetooth_battery_top_margin">5dp</dimen>
|
||||||
|
<dimen name="le_bluetooth_battery_start_margin">10dp</dimen>
|
||||||
|
<dimen name="le_bluetooth_summary_drawable_padding">6dp</dimen>
|
||||||
|
<dimen name="le_bluetooth_summary_start_margin">20dp</dimen>
|
||||||
|
<dimen name="le_bluetooth_summary_padding">1.5dp</dimen>
|
||||||
|
|
||||||
<!-- Developer option bluetooth settings dialog -->
|
<!-- Developer option bluetooth settings dialog -->
|
||||||
<dimen name="developer_option_dialog_margin_start">8dp</dimen>
|
<dimen name="developer_option_dialog_margin_start">8dp</dimen>
|
||||||
<dimen name="developer_option_dialog_margin_top">8dp</dimen>
|
<dimen name="developer_option_dialog_margin_top">8dp</dimen>
|
||||||
|
|||||||
@@ -5405,7 +5405,7 @@
|
|||||||
<!-- Description for the accessibility button in gesture navigation. Explain how this page works. [CHAR LIMIT=NONE] -->
|
<!-- Description for the accessibility button in gesture navigation. Explain how this page works. [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_button_gesture_description"><b>To get started</b>\n1. Go to accessibility settings\n2. Select a feature and tap the shortcut\n3. Choose whether you want to use a button or gesture to access the feature</string>
|
<string name="accessibility_button_gesture_description"><b>To get started</b>\n1. Go to accessibility settings\n2. Select a feature and tap the shortcut\n3. Choose whether you want to use a button or gesture to access the feature</string>
|
||||||
<!-- Description for the accessibility button page. Explain how this page works. [CHAR LIMIT=NONE] -->
|
<!-- Description for the accessibility button page. Explain how this page works. [CHAR LIMIT=NONE] -->
|
||||||
<string name="accessibility_button_description"><b>To get started</b>\n1. Go to accessibility settings\n2. Select a feature and tap the shortcut\n3. Choose the button to use to access the feature</string>
|
<string name="accessibility_button_description"><b>To get started</b>\n1. Go to accessibility settings\n2. Select a feature and tap the shortcut\n3. Choose the button to access the feature</string>
|
||||||
<!-- Title for the button or gesture of the accessibility button. [CHAR LIMIT=35] -->
|
<!-- Title for the button or gesture of the accessibility button. [CHAR LIMIT=35] -->
|
||||||
<string name="accessibility_button_or_gesture_title">Use button or gesture</string>
|
<string name="accessibility_button_or_gesture_title">Use button or gesture</string>
|
||||||
<!-- Title for the location of the accessibility button. [CHAR LIMIT=35] -->
|
<!-- Title for the location of the accessibility button. [CHAR LIMIT=35] -->
|
||||||
@@ -8296,7 +8296,7 @@
|
|||||||
<string name="keywords_sounds_and_notifications_interruptions">dont don\u2019t disturb, interrupt, interruption, break</string>
|
<string name="keywords_sounds_and_notifications_interruptions">dont don\u2019t disturb, interrupt, interruption, break</string>
|
||||||
<string name="keywords_app">RAM</string>
|
<string name="keywords_app">RAM</string>
|
||||||
<string name="keywords_location">nearby, location, history, reporting, GPS</string>
|
<string name="keywords_location">nearby, location, history, reporting, GPS</string>
|
||||||
<string name="keywords_accounts">account, add an account, work profile, add account</string>
|
<string name="keywords_accounts">account, add an account, work profile, add account, remove, delete</string>
|
||||||
<string name="keywords_users">restriction, restrict, restricted</string>
|
<string name="keywords_users">restriction, restrict, restricted</string>
|
||||||
<string name="keywords_keyboard_and_ime">text correction, correct, sound, vibrate, auto, language, gesture, suggest, suggestion, theme, offensive, word, type, emoji, international</string>
|
<string name="keywords_keyboard_and_ime">text correction, correct, sound, vibrate, auto, language, gesture, suggest, suggestion, theme, offensive, word, type, emoji, international</string>
|
||||||
<string name="keywords_reset_apps">reset, preferences, default</string>
|
<string name="keywords_reset_apps">reset, preferences, default</string>
|
||||||
@@ -9852,7 +9852,7 @@
|
|||||||
<string name="zen_mode_people_calls_messages_section_title">Who can interrupt</string>
|
<string name="zen_mode_people_calls_messages_section_title">Who can interrupt</string>
|
||||||
|
|
||||||
<!-- [CHAR LIMIT=NONE] Zen mode settings: people screen footer -->
|
<!-- [CHAR LIMIT=NONE] Zen mode settings: people screen footer -->
|
||||||
<string name="zen_mode_people_footer" translatable="false">Even if messaging or calling apps can\u0027t notify you, people you choose here can still reach you through those apps</string>
|
<string name="zen_mode_people_footer">Even if messaging or calling apps can\u0027t notify you, people you choose here can still reach you through those apps</string>
|
||||||
|
|
||||||
<!-- [CHAR LIMIT=40] Zen mode settings: Allow calls toggle title -->
|
<!-- [CHAR LIMIT=40] Zen mode settings: Allow calls toggle title -->
|
||||||
<string name="zen_mode_calls_title">Calls</string>
|
<string name="zen_mode_calls_title">Calls</string>
|
||||||
@@ -11596,11 +11596,6 @@
|
|||||||
<!-- Title for the See more preference item in Special app access settings [CHAR LIMIT=30] -->
|
<!-- Title for the See more preference item in Special app access settings [CHAR LIMIT=30] -->
|
||||||
<string name="special_access_more">See more</string>
|
<string name="special_access_more">See more</string>
|
||||||
|
|
||||||
<!-- Developer option to convert to file encryption - final warning -->
|
|
||||||
<string name="confirm_convert_to_fbe_warning">Really wipe user data and convert to file encryption?</string>
|
|
||||||
<!-- Developer option to convert to file encryption - final button -->
|
|
||||||
<string name="button_confirm_convert_fbe">Wipe and convert</string>
|
|
||||||
|
|
||||||
<!-- Reset rate-limiting in the system service ShortcutManager. "ShortcutManager" is the name of a system service and not translatable.
|
<!-- Reset rate-limiting in the system service ShortcutManager. "ShortcutManager" is the name of a system service and not translatable.
|
||||||
If the word "rate-limit" is hard to translate, use "Reset ShortcutManager API call limit" as the source text, which means
|
If the word "rate-limit" is hard to translate, use "Reset ShortcutManager API call limit" as the source text, which means
|
||||||
the same thing in this context.
|
the same thing in this context.
|
||||||
|
|||||||
@@ -34,6 +34,14 @@
|
|||||||
settings:searchable="false"
|
settings:searchable="false"
|
||||||
settings:controller="com.android.settings.bluetooth.AdvancedBluetoothDetailsHeaderController"/>
|
settings:controller="com.android.settings.bluetooth.AdvancedBluetoothDetailsHeaderController"/>
|
||||||
|
|
||||||
|
<com.android.settingslib.widget.LayoutPreference
|
||||||
|
android:key="le_audio_bluetooth_device_header"
|
||||||
|
android:layout="@layout/le_audio_bt_entity_header"
|
||||||
|
android:selectable="false"
|
||||||
|
settings:allowDividerBelow="true"
|
||||||
|
settings:searchable="false"
|
||||||
|
settings:controller="com.android.settings.bluetooth.LeAudioBluetoothDetailsHeaderController"/>
|
||||||
|
|
||||||
<com.android.settingslib.widget.ActionButtonsPreference
|
<com.android.settingslib.widget.ActionButtonsPreference
|
||||||
android:key="action_buttons"
|
android:key="action_buttons"
|
||||||
settings:allowDividerBelow="true"/>
|
settings:allowDividerBelow="true"/>
|
||||||
|
|||||||
@@ -92,12 +92,6 @@
|
|||||||
android:summary="@string/runningservices_settings_summary"
|
android:summary="@string/runningservices_settings_summary"
|
||||||
android:fragment="com.android.settings.applications.RunningServices" />
|
android:fragment="com.android.settings.applications.RunningServices" />
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="convert_to_file_encryption"
|
|
||||||
android:title="@string/convert_to_file_encryption"
|
|
||||||
android:summary="@string/convert_to_file_encryption_enabled"
|
|
||||||
android:fragment="com.android.settings.applications.ConvertToFbe" />
|
|
||||||
|
|
||||||
<com.android.settings.development.ColorModePreference
|
<com.android.settings.development.ColorModePreference
|
||||||
android:key="picture_color_mode"
|
android:key="picture_color_mode"
|
||||||
android:title="@string/picture_color_mode"
|
android:title="@string/picture_color_mode"
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ import androidx.preference.PreferenceViewHolder;
|
|||||||
|
|
||||||
import com.android.settingslib.widget.FooterPreference;
|
import com.android.settingslib.widget.FooterPreference;
|
||||||
|
|
||||||
/**
|
/** A custom preference acting as footer of a page. Disables the movement method by default. */
|
||||||
* A custom preference acting as footer of a page. Disables the movement method by default.
|
|
||||||
*/
|
|
||||||
public final class AccessibilityFooterPreference extends FooterPreference {
|
public final class AccessibilityFooterPreference extends FooterPreference {
|
||||||
|
|
||||||
private boolean mLinkEnabled;
|
private boolean mLinkEnabled;
|
||||||
@@ -46,12 +44,16 @@ public final class AccessibilityFooterPreference extends FooterPreference {
|
|||||||
|
|
||||||
final TextView title = holder.itemView.findViewById(android.R.id.title);
|
final TextView title = holder.itemView.findViewById(android.R.id.title);
|
||||||
if (mLinkEnabled) {
|
if (mLinkEnabled) {
|
||||||
// When a TextView has a movement method, it will set the view to clickable. This makes
|
// When a TextView has a movement method, it will set the view to focusable and
|
||||||
// View.onTouchEvent always return true and consumes the touch event, essentially
|
// clickable. This makes View.onTouchEvent always return true and consumes the touch
|
||||||
// nullifying any return values of MovementMethod.onTouchEvent.
|
// event, essentially nullifying any return values of MovementMethod.onTouchEvent.
|
||||||
// To still allow propagating touch events to the parent when this view doesn't have
|
// To still allow propagating touch events to the parent when this view doesn't have
|
||||||
// links, we only set the movement method here if the text contains links.
|
// links, we only set the movement method here if the text contains links.
|
||||||
title.setMovementMethod(LinkMovementMethod.getInstance());
|
title.setMovementMethod(LinkMovementMethod.getInstance());
|
||||||
|
|
||||||
|
// Groups of related title and link content by making the container focusable,
|
||||||
|
// then make all the children inside not focusable.
|
||||||
|
title.setFocusable(false);
|
||||||
} else {
|
} else {
|
||||||
title.setMovementMethod(/* movement= */ null);
|
title.setMovementMethod(/* movement= */ null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,5 +122,8 @@ public class AccessibilityFooterPreferenceController extends BasePreferenceContr
|
|||||||
} else {
|
} else {
|
||||||
footerPreference.setLinkEnabled(false);
|
footerPreference.setLinkEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Grouping subcomponents to make more accessible.
|
||||||
|
footerPreference.setSelectable(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ package com.android.settings.accessibility;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
import androidx.preference.SwitchPreference;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.core.TogglePreferenceController;
|
import com.android.settings.core.TogglePreferenceController;
|
||||||
|
|
||||||
@@ -27,6 +30,7 @@ import com.android.settings.core.TogglePreferenceController;
|
|||||||
*/
|
*/
|
||||||
public class HighTextContrastPreferenceController extends TogglePreferenceController implements
|
public class HighTextContrastPreferenceController extends TogglePreferenceController implements
|
||||||
TextReadingResetController.ResetStateListener {
|
TextReadingResetController.ResetStateListener {
|
||||||
|
private SwitchPreference mSwitchPreference;
|
||||||
|
|
||||||
public HighTextContrastPreferenceController(Context context, String preferenceKey) {
|
public HighTextContrastPreferenceController(Context context, String preferenceKey) {
|
||||||
super(context, preferenceKey);
|
super(context, preferenceKey);
|
||||||
@@ -54,8 +58,15 @@ public class HighTextContrastPreferenceController extends TogglePreferenceContro
|
|||||||
return R.string.menu_key_accessibility;
|
return R.string.menu_key_accessibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
mSwitchPreference = screen.findPreference(getPreferenceKey());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resetState() {
|
public void resetState() {
|
||||||
setChecked(false);
|
setChecked(false);
|
||||||
|
updateState(mSwitchPreference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -564,13 +564,6 @@ public abstract class ToggleFeaturePreferenceFragment extends SettingsPreference
|
|||||||
createFooterPreference(getPreferenceScreen(), mDescription,
|
createFooterPreference(getPreferenceScreen(), mDescription,
|
||||||
getString(R.string.accessibility_introduction_title, mPackageName));
|
getString(R.string.accessibility_introduction_title, mPackageName));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TextUtils.isEmpty(mHtmlDescription) && TextUtils.isEmpty(mDescription)) {
|
|
||||||
final CharSequence defaultDescription =
|
|
||||||
getText(R.string.accessibility_service_default_description);
|
|
||||||
createFooterPreference(getPreferenceScreen(), defaultDescription,
|
|
||||||
getString(R.string.accessibility_introduction_title, mPackageName));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2016 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.applications;
|
|
||||||
|
|
||||||
import android.app.settings.SettingsEnums;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Button;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
|
||||||
import com.android.settings.SettingsPreferenceFragment;
|
|
||||||
|
|
||||||
public class ConfirmConvertToFbe extends SettingsPreferenceFragment {
|
|
||||||
static final String TAG = "ConfirmConvertToFBE";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState) {
|
|
||||||
View rootView = inflater.inflate(R.layout.confirm_convert_fbe, null);
|
|
||||||
|
|
||||||
final Button button = (Button) rootView.findViewById(R.id.button_confirm_convert_fbe);
|
|
||||||
button.setOnClickListener(new View.OnClickListener() {
|
|
||||||
public void onClick(View v) {
|
|
||||||
Intent intent = new Intent(Intent.ACTION_FACTORY_RESET);
|
|
||||||
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
|
||||||
intent.setPackage("android");
|
|
||||||
intent.putExtra(Intent.EXTRA_REASON, "convert_fbe");
|
|
||||||
getActivity().sendBroadcast(intent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return rootView;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMetricsCategory() {
|
|
||||||
return SettingsEnums.CONVERT_FBE_CONFIRM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 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.applications;
|
|
||||||
|
|
||||||
import android.annotation.Nullable;
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.settings.SettingsEnums;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.res.Resources;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.Button;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
|
||||||
import com.android.settings.core.InstrumentedFragment;
|
|
||||||
import com.android.settings.core.SubSettingLauncher;
|
|
||||||
import com.android.settings.password.ChooseLockSettingsHelper;
|
|
||||||
|
|
||||||
/* Class to prompt for conversion of userdata to file based encryption
|
|
||||||
*/
|
|
||||||
public class ConvertToFbe extends InstrumentedFragment {
|
|
||||||
static final String TAG = "ConvertToFBE";
|
|
||||||
private static final int KEYGUARD_REQUEST = 55;
|
|
||||||
|
|
||||||
private boolean runKeyguardConfirmation(int request) {
|
|
||||||
Resources res = getActivity().getResources();
|
|
||||||
final ChooseLockSettingsHelper.Builder builder =
|
|
||||||
new ChooseLockSettingsHelper.Builder(getActivity(), this);
|
|
||||||
return builder.setRequestCode(request)
|
|
||||||
.setTitle(res.getText(R.string.convert_to_file_encryption))
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
||||||
super.onCreate(savedInstanceState);
|
|
||||||
getActivity().setTitle(R.string.convert_to_file_encryption);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
|
||||||
Bundle savedInstanceState) {
|
|
||||||
View rootView = inflater.inflate(R.layout.convert_fbe, null);
|
|
||||||
|
|
||||||
final Button button = rootView.findViewById(R.id.button_convert_fbe);
|
|
||||||
button.setOnClickListener(v -> {
|
|
||||||
if (!runKeyguardConfirmation(KEYGUARD_REQUEST)) {
|
|
||||||
convert();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return rootView;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
|
||||||
|
|
||||||
if (requestCode != KEYGUARD_REQUEST) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the user entered a valid keyguard credential, start the conversion
|
|
||||||
// process
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
convert();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void convert() {
|
|
||||||
new SubSettingLauncher(getContext())
|
|
||||||
.setDestination(ConfirmConvertToFbe.class.getName())
|
|
||||||
.setTitleRes(R.string.convert_to_file_encryption)
|
|
||||||
.setSourceMetricsCategory(getMetricsCategory())
|
|
||||||
.launch();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getMetricsCategory() {
|
|
||||||
return SettingsEnums.CONVERT_FBE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -81,9 +81,11 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
|||||||
private static final int STAGE_CENTER = 0;
|
private static final int STAGE_CENTER = 0;
|
||||||
private static final int STAGE_GUIDED = 1;
|
private static final int STAGE_GUIDED = 1;
|
||||||
private static final int STAGE_FINGERTIP = 2;
|
private static final int STAGE_FINGERTIP = 2;
|
||||||
private static final int STAGE_EDGES = 3;
|
private static final int STAGE_LEFT_EDGE = 3;
|
||||||
|
private static final int STAGE_RIGHT_EDGE = 4;
|
||||||
|
|
||||||
@IntDef({STAGE_UNKNOWN, STAGE_CENTER, STAGE_GUIDED, STAGE_FINGERTIP, STAGE_EDGES})
|
@IntDef({STAGE_UNKNOWN, STAGE_CENTER, STAGE_GUIDED, STAGE_FINGERTIP, STAGE_LEFT_EDGE,
|
||||||
|
STAGE_RIGHT_EDGE})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
private @interface EnrollStage {}
|
private @interface EnrollStage {}
|
||||||
|
|
||||||
@@ -132,7 +134,8 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
|||||||
private boolean mIsAccessibilityEnabled;
|
private boolean mIsAccessibilityEnabled;
|
||||||
private LottieAnimationView mIllustrationLottie;
|
private LottieAnimationView mIllustrationLottie;
|
||||||
private boolean mHaveShownUdfpsTipLottie;
|
private boolean mHaveShownUdfpsTipLottie;
|
||||||
private boolean mHaveShownUdfpsSideLottie;
|
private boolean mHaveShownUdfpsLeftEdgeLottie;
|
||||||
|
private boolean mHaveShownUdfpsRightEdgeLottie;
|
||||||
private boolean mShouldShowLottie;
|
private boolean mShouldShowLottie;
|
||||||
|
|
||||||
private OrientationEventListener mOrientationEventListener;
|
private OrientationEventListener mOrientationEventListener;
|
||||||
@@ -372,12 +375,31 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STAGE_EDGES:
|
case STAGE_LEFT_EDGE:
|
||||||
setHeaderText(R.string.security_settings_udfps_enroll_edge_title);
|
setHeaderText(R.string.security_settings_udfps_enroll_edge_title);
|
||||||
if (!mHaveShownUdfpsSideLottie && mIllustrationLottie != null) {
|
if (!mHaveShownUdfpsLeftEdgeLottie && mIllustrationLottie != null) {
|
||||||
mHaveShownUdfpsSideLottie = true;
|
mHaveShownUdfpsLeftEdgeLottie = true;
|
||||||
setDescriptionText("");
|
setDescriptionText("");
|
||||||
mIllustrationLottie.setAnimation(R.raw.udfps_edge_hint_lottie);
|
mIllustrationLottie.setAnimation(R.raw.udfps_left_edge_hint_lottie);
|
||||||
|
mIllustrationLottie.setVisibility(View.VISIBLE);
|
||||||
|
mIllustrationLottie.playAnimation();
|
||||||
|
mIllustrationLottie.setContentDescription(
|
||||||
|
getString(R.string.security_settings_udfps_side_fingerprint_help));
|
||||||
|
} else if (mIllustrationLottie == null) {
|
||||||
|
if (isStageHalfCompleted()) {
|
||||||
|
setDescriptionText(
|
||||||
|
R.string.security_settings_fingerprint_enroll_repeat_message);
|
||||||
|
} else {
|
||||||
|
setDescriptionText(R.string.security_settings_udfps_enroll_edge_message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STAGE_RIGHT_EDGE:
|
||||||
|
setHeaderText(R.string.security_settings_udfps_enroll_edge_title);
|
||||||
|
if (!mHaveShownUdfpsRightEdgeLottie && mIllustrationLottie != null) {
|
||||||
|
mHaveShownUdfpsRightEdgeLottie = true;
|
||||||
|
setDescriptionText("");
|
||||||
|
mIllustrationLottie.setAnimation(R.raw.udfps_right_edge_hint_lottie);
|
||||||
mIllustrationLottie.setVisibility(View.VISIBLE);
|
mIllustrationLottie.setVisibility(View.VISIBLE);
|
||||||
mIllustrationLottie.playAnimation();
|
mIllustrationLottie.playAnimation();
|
||||||
mIllustrationLottie.setContentDescription(
|
mIllustrationLottie.setContentDescription(
|
||||||
@@ -422,8 +444,10 @@ public class FingerprintEnrollEnrolling extends BiometricsEnrollEnrolling {
|
|||||||
return STAGE_GUIDED;
|
return STAGE_GUIDED;
|
||||||
} else if (progressSteps < getStageThresholdSteps(2)) {
|
} else if (progressSteps < getStageThresholdSteps(2)) {
|
||||||
return STAGE_FINGERTIP;
|
return STAGE_FINGERTIP;
|
||||||
|
} else if (progressSteps < getStageThresholdSteps(3)) {
|
||||||
|
return STAGE_LEFT_EDGE;
|
||||||
} else {
|
} else {
|
||||||
return STAGE_EDGES;
|
return STAGE_RIGHT_EDGE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package com.android.settings.bluetooth;
|
package com.android.settings.bluetooth;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -53,7 +54,10 @@ public class BluetoothDetailsHeaderController extends BluetoothDetailsController
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAvailable() {
|
public boolean isAvailable() {
|
||||||
return !Utils.isAdvancedDetailsHeader(mCachedDevice.getDevice());
|
boolean hasLeAudio = mCachedDevice.getConnectableProfiles()
|
||||||
|
.stream()
|
||||||
|
.anyMatch(profile -> profile.getProfileId() == BluetoothProfile.LE_AUDIO);
|
||||||
|
return !Utils.isAdvancedDetailsHeader(mCachedDevice.getDevice()) && !hasLeAudio;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -16,10 +16,12 @@
|
|||||||
|
|
||||||
package com.android.settings.bluetooth;
|
package com.android.settings.bluetooth;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothCsipSetCoordinator;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.bluetooth.BluetoothProfile;
|
import android.bluetooth.BluetoothProfile;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
@@ -31,6 +33,7 @@ import androidx.preference.SwitchPreference;
|
|||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settingslib.bluetooth.A2dpProfile;
|
import com.android.settingslib.bluetooth.A2dpProfile;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
|
import com.android.settingslib.bluetooth.LeAudioProfile;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||||
@@ -39,7 +42,10 @@ import com.android.settingslib.bluetooth.PanProfile;
|
|||||||
import com.android.settingslib.bluetooth.PbapServerProfile;
|
import com.android.settingslib.bluetooth.PbapServerProfile;
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class adds switches for toggling the individual profiles that a Bluetooth device
|
* This class adds switches for toggling the individual profiles that a Bluetooth device
|
||||||
@@ -48,8 +54,11 @@ import java.util.List;
|
|||||||
public class BluetoothDetailsProfilesController extends BluetoothDetailsController
|
public class BluetoothDetailsProfilesController extends BluetoothDetailsController
|
||||||
implements Preference.OnPreferenceClickListener,
|
implements Preference.OnPreferenceClickListener,
|
||||||
LocalBluetoothProfileManager.ServiceListener {
|
LocalBluetoothProfileManager.ServiceListener {
|
||||||
|
private static final String TAG = "BtDetailsProfilesCtrl";
|
||||||
|
|
||||||
private static final String KEY_PROFILES_GROUP = "bluetooth_profiles";
|
private static final String KEY_PROFILES_GROUP = "bluetooth_profiles";
|
||||||
private static final String KEY_BOTTOM_PREFERENCE = "bottom_preference";
|
private static final String KEY_BOTTOM_PREFERENCE = "bottom_preference";
|
||||||
|
private static final String HEADSET_CLIENT = "HEADSET_CLIENT";
|
||||||
private static final int ORDINAL = 99;
|
private static final int ORDINAL = 99;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -58,6 +67,9 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
|||||||
private LocalBluetoothManager mManager;
|
private LocalBluetoothManager mManager;
|
||||||
private LocalBluetoothProfileManager mProfileManager;
|
private LocalBluetoothProfileManager mProfileManager;
|
||||||
private CachedBluetoothDevice mCachedDevice;
|
private CachedBluetoothDevice mCachedDevice;
|
||||||
|
private List<CachedBluetoothDevice> mAllOfCachedDevices;
|
||||||
|
private Map<String, List<CachedBluetoothDevice>> mProfileDeviceMap =
|
||||||
|
new HashMap<String, List<CachedBluetoothDevice>>();
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
PreferenceCategory mProfilesContainer;
|
PreferenceCategory mProfilesContainer;
|
||||||
@@ -68,6 +80,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
|||||||
mManager = manager;
|
mManager = manager;
|
||||||
mProfileManager = mManager.getProfileManager();
|
mProfileManager = mManager.getProfileManager();
|
||||||
mCachedDevice = device;
|
mCachedDevice = device;
|
||||||
|
mAllOfCachedDevices = getAllOfCachedBluetoothDevices();
|
||||||
lifecycle.addObserver(this);
|
lifecycle.addObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,11 +113,66 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Refreshes the state for an existing SwitchPreference for a profile.
|
* Refreshes the state for an existing SwitchPreference for a profile.
|
||||||
|
* If the LeAudio profile is enabled on the LeAudio devices, then the SwitchPreferences of
|
||||||
|
* A2dp profile and Hfp profile are graied out.
|
||||||
*/
|
*/
|
||||||
private void refreshProfilePreference(SwitchPreference profilePref,
|
private void refreshProfilePreference(SwitchPreference profilePref,
|
||||||
LocalBluetoothProfile profile) {
|
LocalBluetoothProfile profile) {
|
||||||
BluetoothDevice device = mCachedDevice.getDevice();
|
BluetoothDevice device = mCachedDevice.getDevice();
|
||||||
profilePref.setEnabled(!mCachedDevice.isBusy());
|
boolean isLeAudioEnabled = false;
|
||||||
|
if (profile instanceof A2dpProfile || HEADSET_CLIENT.equals(profile.toString())) {
|
||||||
|
LocalBluetoothProfile leAudio = mProfileManager.getLeAudioProfile();
|
||||||
|
if (leAudio != null) {
|
||||||
|
List<CachedBluetoothDevice> leAudioDeviceList = mProfileDeviceMap.get(
|
||||||
|
leAudio.toString());
|
||||||
|
if (leAudioDeviceList != null
|
||||||
|
&& leAudioDeviceList.stream()
|
||||||
|
.anyMatch(item -> leAudio.isEnabled(item.getDevice()))) {
|
||||||
|
isLeAudioEnabled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isLeAudioEnabled) {
|
||||||
|
// If the LeAudio profile is enabled on the LeAudio devices, then the
|
||||||
|
// SwitchPreferences of A2dp profile and Hfp profile are graied out.
|
||||||
|
profilePref.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
List<CachedBluetoothDevice> deviceList = mProfileDeviceMap.get(
|
||||||
|
profile.toString());
|
||||||
|
boolean isBusy = deviceList != null
|
||||||
|
&& deviceList.stream().anyMatch(item -> item.isBusy());
|
||||||
|
profilePref.setEnabled(!isBusy);
|
||||||
|
}
|
||||||
|
} else if (profile instanceof LeAudioProfile) {
|
||||||
|
List<CachedBluetoothDevice> leAudioDeviceList = mProfileDeviceMap.get(
|
||||||
|
profile.toString());
|
||||||
|
boolean isLeAudioProfileEnable =
|
||||||
|
leAudioDeviceList != null && leAudioDeviceList.stream().anyMatch(
|
||||||
|
item -> profile.isEnabled(item.getDevice()));
|
||||||
|
boolean isBusy = leAudioDeviceList != null
|
||||||
|
&& leAudioDeviceList.stream().anyMatch(item -> item.isBusy());
|
||||||
|
if (isLeAudioProfileEnable && !isBusy) {
|
||||||
|
LocalBluetoothProfile a2dp = mProfileManager.getA2dpProfile();
|
||||||
|
LocalBluetoothProfile hfp = mProfileManager.getHfpClientProfile();
|
||||||
|
// If the LeAudio profile is enabled on the LeAudio devices, then the
|
||||||
|
// SwitchPreferences of A2dp profile and Hfp profile are graied out.
|
||||||
|
if (a2dp != null) {
|
||||||
|
SwitchPreference pref = mProfilesContainer.findPreference(a2dp.toString());
|
||||||
|
if (pref != null) {
|
||||||
|
pref.setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hfp != null) {
|
||||||
|
SwitchPreference pref = mProfilesContainer.findPreference(hfp.toString());
|
||||||
|
if (pref != null) {
|
||||||
|
pref.setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
profilePref.setEnabled(!isBusy);
|
||||||
|
} else {
|
||||||
|
profilePref.setEnabled(!mCachedDevice.isBusy());
|
||||||
|
}
|
||||||
|
|
||||||
if (profile instanceof MapProfile) {
|
if (profile instanceof MapProfile) {
|
||||||
profilePref.setChecked(device.getMessageAccessPermission()
|
profilePref.setChecked(device.getMessageAccessPermission()
|
||||||
== BluetoothDevice.ACCESS_ALLOWED);
|
== BluetoothDevice.ACCESS_ALLOWED);
|
||||||
@@ -127,7 +195,7 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
|||||||
highQualityPref.setVisible(true);
|
highQualityPref.setVisible(true);
|
||||||
highQualityPref.setTitle(a2dp.getHighQualityAudioOptionLabel(device));
|
highQualityPref.setTitle(a2dp.getHighQualityAudioOptionLabel(device));
|
||||||
highQualityPref.setChecked(a2dp.isHighQualityAudioEnabled(device));
|
highQualityPref.setChecked(a2dp.isHighQualityAudioEnabled(device));
|
||||||
highQualityPref.setEnabled(!mCachedDevice.isBusy());
|
highQualityPref.setEnabled(!mCachedDevice.isBusy() && !isLeAudioEnabled);
|
||||||
} else {
|
} else {
|
||||||
highQualityPref.setVisible(false);
|
highQualityPref.setVisible(false);
|
||||||
}
|
}
|
||||||
@@ -148,6 +216,12 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
|||||||
if (profile instanceof MapProfile) {
|
if (profile instanceof MapProfile) {
|
||||||
bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
|
bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (profile instanceof LeAudioProfile) {
|
||||||
|
enableLeAudioProfile(profile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
profile.setEnabled(bluetoothDevice, true);
|
profile.setEnabled(bluetoothDevice, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,8 +229,14 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
|||||||
* Helper method to disable a profile for a device
|
* Helper method to disable a profile for a device
|
||||||
*/
|
*/
|
||||||
private void disableProfile(LocalBluetoothProfile profile) {
|
private void disableProfile(LocalBluetoothProfile profile) {
|
||||||
|
if (profile instanceof LeAudioProfile) {
|
||||||
|
disableLeAudioProfile(profile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final BluetoothDevice bluetoothDevice = mCachedDevice.getDevice();
|
final BluetoothDevice bluetoothDevice = mCachedDevice.getDevice();
|
||||||
profile.setEnabled(bluetoothDevice, false);
|
profile.setEnabled(bluetoothDevice, false);
|
||||||
|
|
||||||
if (profile instanceof MapProfile) {
|
if (profile instanceof MapProfile) {
|
||||||
bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED);
|
bluetoothDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED);
|
||||||
} else if (profile instanceof PbapServerProfile) {
|
} else if (profile instanceof PbapServerProfile) {
|
||||||
@@ -190,14 +270,33 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to get the list of connectable and special profiles.
|
* Helper to get the list of connectable and special profiles.
|
||||||
*/
|
*/
|
||||||
private List<LocalBluetoothProfile> getProfiles() {
|
private List<LocalBluetoothProfile> getProfiles() {
|
||||||
List<LocalBluetoothProfile> result = mCachedDevice.getConnectableProfiles();
|
List<LocalBluetoothProfile> result = new ArrayList<LocalBluetoothProfile>();
|
||||||
final BluetoothDevice device = mCachedDevice.getDevice();
|
mProfileDeviceMap.clear();
|
||||||
|
if (mAllOfCachedDevices == null || mAllOfCachedDevices.isEmpty()) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
for (CachedBluetoothDevice cachedItem : mAllOfCachedDevices) {
|
||||||
|
List<LocalBluetoothProfile> tmpResult = cachedItem.getConnectableProfiles();
|
||||||
|
for (LocalBluetoothProfile profile : tmpResult) {
|
||||||
|
if (mProfileDeviceMap.containsKey(profile.toString())) {
|
||||||
|
mProfileDeviceMap.get(profile.toString()).add(cachedItem);
|
||||||
|
Log.d(TAG, "getProfiles: " + profile.toString() + " add device "
|
||||||
|
+ cachedItem.getDevice().getAnonymizedAddress());
|
||||||
|
} else {
|
||||||
|
List<CachedBluetoothDevice> tmpCachedDeviceList =
|
||||||
|
new ArrayList<CachedBluetoothDevice>();
|
||||||
|
tmpCachedDeviceList.add(cachedItem);
|
||||||
|
mProfileDeviceMap.put(profile.toString(), tmpCachedDeviceList);
|
||||||
|
result.add(profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final BluetoothDevice device = mCachedDevice.getDevice();
|
||||||
final int pbapPermission = device.getPhonebookAccessPermission();
|
final int pbapPermission = device.getPhonebookAccessPermission();
|
||||||
// Only provide PBAP cabability if the client device has requested PBAP.
|
// Only provide PBAP cabability if the client device has requested PBAP.
|
||||||
if (pbapPermission != BluetoothDevice.ACCESS_UNKNOWN) {
|
if (pbapPermission != BluetoothDevice.ACCESS_UNKNOWN) {
|
||||||
@@ -210,10 +309,93 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
|||||||
if (mapPermission != BluetoothDevice.ACCESS_UNKNOWN) {
|
if (mapPermission != BluetoothDevice.ACCESS_UNKNOWN) {
|
||||||
result.add(mapProfile);
|
result.add(mapProfile);
|
||||||
}
|
}
|
||||||
|
Log.d(TAG, "getProfiles:result:" + result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<CachedBluetoothDevice> getAllOfCachedBluetoothDevices() {
|
||||||
|
List<CachedBluetoothDevice> cachedBluetoothDevices = new ArrayList<>();
|
||||||
|
if (mCachedDevice == null) {
|
||||||
|
return cachedBluetoothDevices;
|
||||||
|
}
|
||||||
|
cachedBluetoothDevices.add(mCachedDevice);
|
||||||
|
if (mCachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
|
||||||
|
for (CachedBluetoothDevice member : mCachedDevice.getMemberDevice()) {
|
||||||
|
cachedBluetoothDevices.add(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cachedBluetoothDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When user disable the Le Audio profile, the system needs to do two things.
|
||||||
|
* 1) Disable the Le Audio profile for each of the Le Audio devices.
|
||||||
|
* 2) Enable the A2dp profile and Hfp profile for the associated device. The system can't
|
||||||
|
* enable the A2dp profile and Hfp profile if the Le Audio profile is enabled.
|
||||||
|
*
|
||||||
|
* @param profile the LeAudio profile
|
||||||
|
*/
|
||||||
|
private void disableLeAudioProfile(LocalBluetoothProfile profile) {
|
||||||
|
if (profile == null || mProfileDeviceMap.get(profile.toString()) == null) {
|
||||||
|
Log.e(TAG, "There is no the LE profile or no device in mProfileDeviceMap. Do nothing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (CachedBluetoothDevice leAudioDevice : mProfileDeviceMap.get(profile.toString())) {
|
||||||
|
profile.setEnabled(leAudioDevice.getDevice(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalBluetoothProfile a2dp = mProfileManager.getA2dpProfile();
|
||||||
|
LocalBluetoothProfile hfp = mProfileManager.getHfpClientProfile();
|
||||||
|
if (a2dp != null && mProfileDeviceMap.get(a2dp.toString()) != null) {
|
||||||
|
for (CachedBluetoothDevice a2dpDevice : mProfileDeviceMap.get(a2dp.toString())) {
|
||||||
|
if (!a2dp.isEnabled(a2dpDevice.getDevice())) {
|
||||||
|
a2dp.setEnabled(a2dpDevice.getDevice(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hfp != null && mProfileDeviceMap.get(hfp.toString()) != null) {
|
||||||
|
for (CachedBluetoothDevice hfpDevice : mProfileDeviceMap.get(hfp.toString())) {
|
||||||
|
if (!hfp.isEnabled(hfpDevice.getDevice())) {
|
||||||
|
hfp.setEnabled(hfpDevice.getDevice(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When user enable the Le Audio profile, the system needs to do two things.
|
||||||
|
* 1) Disable the A2dp profile and Hfp profile for the associated device. The system can't
|
||||||
|
* enable the Le Audio if the A2dp profile and Hfp profile are enabled.
|
||||||
|
* 2) Enable the Le Audio profile for each of the Le Audio devices.
|
||||||
|
*
|
||||||
|
* @param profile the LeAudio profile
|
||||||
|
*/
|
||||||
|
private void enableLeAudioProfile(LocalBluetoothProfile profile) {
|
||||||
|
if (profile == null || mProfileDeviceMap.get(profile.toString()) == null) {
|
||||||
|
Log.e(TAG, "There is no the LE profile or no device in mProfileDeviceMap. Do nothing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LocalBluetoothProfile a2dp = mProfileManager.getA2dpProfile();
|
||||||
|
LocalBluetoothProfile hfp = mProfileManager.getHfpClientProfile();
|
||||||
|
if (a2dp != null && mProfileDeviceMap.get(a2dp.toString()) != null) {
|
||||||
|
for (CachedBluetoothDevice a2dpDevice : mProfileDeviceMap.get(a2dp.toString())) {
|
||||||
|
if (a2dp.isEnabled(a2dpDevice.getDevice())) {
|
||||||
|
a2dp.setEnabled(a2dpDevice.getDevice(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hfp != null && mProfileDeviceMap.get(hfp.toString()) != null) {
|
||||||
|
for (CachedBluetoothDevice hfpDevice : mProfileDeviceMap.get(hfp.toString())) {
|
||||||
|
if (hfp.isEnabled(hfpDevice.getDevice())) {
|
||||||
|
hfp.setEnabled(hfpDevice.getDevice(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (CachedBluetoothDevice leAudioDevice : mProfileDeviceMap.get(profile.toString())) {
|
||||||
|
profile.setEnabled(leAudioDevice.getDevice(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a helper method to be called after adding a Preference for a profile. If that
|
* This is a helper method to be called after adding a Preference for a profile. If that
|
||||||
* profile happened to be A2dp and the device supports high quality audio, it will add a
|
* profile happened to be A2dp and the device supports high quality audio, it will add a
|
||||||
@@ -243,16 +425,33 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
for (CachedBluetoothDevice item : mAllOfCachedDevices) {
|
||||||
|
item.unregisterCallback(this);
|
||||||
|
}
|
||||||
mProfileManager.removeServiceListener(this);
|
mProfileManager.removeServiceListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
for (CachedBluetoothDevice item : mAllOfCachedDevices) {
|
||||||
|
item.registerCallback(this);
|
||||||
|
}
|
||||||
mProfileManager.addServiceListener(this);
|
mProfileManager.addServiceListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDeviceAttributesChanged() {
|
||||||
|
for (CachedBluetoothDevice item : mAllOfCachedDevices) {
|
||||||
|
item.unregisterCallback(this);
|
||||||
|
}
|
||||||
|
mAllOfCachedDevices = getAllOfCachedBluetoothDevices();
|
||||||
|
for (CachedBluetoothDevice item : mAllOfCachedDevices) {
|
||||||
|
item.registerCallback(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.onDeviceAttributesChanged();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected() {
|
public void onServiceConnected() {
|
||||||
refresh();
|
refresh();
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice);
|
use(AdvancedBluetoothDetailsHeaderController.class).init(mCachedDevice);
|
||||||
|
use(LeAudioBluetoothDetailsHeaderController.class).init(mCachedDevice, mManager);
|
||||||
|
|
||||||
final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(
|
final BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(
|
||||||
context).getBluetoothFeatureProvider(context);
|
context).getBluetoothFeatureProvider(context);
|
||||||
|
|||||||
@@ -0,0 +1,323 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.settings.bluetooth;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothCsipSetCoordinator;
|
||||||
|
import android.bluetooth.BluetoothLeAudio;
|
||||||
|
import android.bluetooth.BluetoothProfile;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.PorterDuff;
|
||||||
|
import android.graphics.PorterDuffColorFilter;
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.core.BasePreferenceController;
|
||||||
|
import com.android.settings.fuelgauge.BatteryMeterView;
|
||||||
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
|
import com.android.settingslib.bluetooth.LeAudioProfile;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||||
|
import com.android.settingslib.core.lifecycle.LifecycleObserver;
|
||||||
|
import com.android.settingslib.core.lifecycle.events.OnDestroy;
|
||||||
|
import com.android.settingslib.core.lifecycle.events.OnStart;
|
||||||
|
import com.android.settingslib.core.lifecycle.events.OnStop;
|
||||||
|
import com.android.settingslib.widget.LayoutPreference;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class adds a header with device name and status (connected/disconnected, etc.).
|
||||||
|
*/
|
||||||
|
public class LeAudioBluetoothDetailsHeaderController extends BasePreferenceController implements
|
||||||
|
LifecycleObserver, OnStart, OnStop, OnDestroy, CachedBluetoothDevice.Callback {
|
||||||
|
private static final String TAG = "LeAudioBtHeaderCtrl";
|
||||||
|
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static final int LEFT_DEVICE_ID =
|
||||||
|
BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_BACK_LEFT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT_OF_CENTER
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_SIDE_LEFT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_TOP_FRONT_LEFT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_TOP_BACK_LEFT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_TOP_SIDE_LEFT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_BOTTOM_FRONT_LEFT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT_WIDE
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_LEFT_SURROUND;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static final int RIGHT_DEVICE_ID =
|
||||||
|
BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_BACK_RIGHT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_SIDE_RIGHT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_TOP_FRONT_RIGHT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_TOP_BACK_RIGHT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_TOP_SIDE_RIGHT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_BOTTOM_FRONT_RIGHT
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT_WIDE
|
||||||
|
| BluetoothLeAudio.AUDIO_LOCATION_RIGHT_SURROUND;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
static final int INVALID_RESOURCE_ID = -1;
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
LayoutPreference mLayoutPreference;
|
||||||
|
private CachedBluetoothDevice mCachedDevice;
|
||||||
|
@VisibleForTesting
|
||||||
|
Handler mHandler = new Handler(Looper.getMainLooper());
|
||||||
|
@VisibleForTesting
|
||||||
|
boolean mIsRegisterCallback = false;
|
||||||
|
|
||||||
|
private LocalBluetoothProfileManager mProfileManager;
|
||||||
|
|
||||||
|
public LeAudioBluetoothDetailsHeaderController(Context context, String prefKey) {
|
||||||
|
super(context, prefKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAvailabilityStatus() {
|
||||||
|
if (mCachedDevice == null || mProfileManager == null) {
|
||||||
|
return CONDITIONALLY_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
boolean hasLeAudio = mCachedDevice.getConnectableProfiles()
|
||||||
|
.stream()
|
||||||
|
.anyMatch(profile -> profile.getProfileId() == BluetoothProfile.LE_AUDIO);
|
||||||
|
|
||||||
|
return !Utils.isAdvancedDetailsHeader(mCachedDevice.getDevice()) && hasLeAudio
|
||||||
|
? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
mLayoutPreference = screen.findPreference(getPreferenceKey());
|
||||||
|
mLayoutPreference.setVisible(isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
if (!isAvailable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mIsRegisterCallback = true;
|
||||||
|
mCachedDevice.registerCallback(this);
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop() {
|
||||||
|
if (!mIsRegisterCallback) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mCachedDevice.unregisterCallback(this);
|
||||||
|
mIsRegisterCallback = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(CachedBluetoothDevice cachedBluetoothDevice,
|
||||||
|
LocalBluetoothManager bluetoothManager) {
|
||||||
|
mCachedDevice = cachedBluetoothDevice;
|
||||||
|
mProfileManager = bluetoothManager.getProfileManager();
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void refresh() {
|
||||||
|
if (mLayoutPreference == null || mCachedDevice == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final ImageView imageView = mLayoutPreference.findViewById(R.id.entity_header_icon);
|
||||||
|
if (imageView != null) {
|
||||||
|
final Pair<Drawable, String> pair =
|
||||||
|
BluetoothUtils.getBtRainbowDrawableWithDescription(mContext, mCachedDevice);
|
||||||
|
imageView.setImageDrawable(pair.first);
|
||||||
|
imageView.setContentDescription(pair.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
final TextView title = mLayoutPreference.findViewById(R.id.entity_header_title);
|
||||||
|
if (title != null) {
|
||||||
|
title.setText(mCachedDevice.getName());
|
||||||
|
}
|
||||||
|
final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary);
|
||||||
|
if (summary != null) {
|
||||||
|
summary.setText(mCachedDevice.getConnectionSummary(true /* shortSummary */));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mCachedDevice.isConnected() || mCachedDevice.isBusy()) {
|
||||||
|
hideAllOfBatteryLayouts();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateBatteryLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
Drawable createBtBatteryIcon(Context context, int level) {
|
||||||
|
final BatteryMeterView.BatteryMeterDrawable drawable =
|
||||||
|
new BatteryMeterView.BatteryMeterDrawable(context,
|
||||||
|
context.getColor(R.color.meter_background_color),
|
||||||
|
context.getResources().getDimensionPixelSize(
|
||||||
|
R.dimen.advanced_bluetooth_battery_meter_width),
|
||||||
|
context.getResources().getDimensionPixelSize(
|
||||||
|
R.dimen.advanced_bluetooth_battery_meter_height));
|
||||||
|
drawable.setBatteryLevel(level);
|
||||||
|
drawable.setColorFilter(new PorterDuffColorFilter(
|
||||||
|
com.android.settings.Utils.getColorAttrDefaultColor(context,
|
||||||
|
android.R.attr.colorControlNormal),
|
||||||
|
PorterDuff.Mode.SRC));
|
||||||
|
return drawable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getBatteryTitleResource(int deviceId) {
|
||||||
|
if (deviceId == LEFT_DEVICE_ID) {
|
||||||
|
return R.id.bt_battery_left_title;
|
||||||
|
}
|
||||||
|
if (deviceId == RIGHT_DEVICE_ID) {
|
||||||
|
return R.id.bt_battery_right_title;
|
||||||
|
}
|
||||||
|
Log.d(TAG, "No resource id. The deviceId is " + deviceId);
|
||||||
|
return INVALID_RESOURCE_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getBatterySummaryResource(int deviceId) {
|
||||||
|
if (deviceId == LEFT_DEVICE_ID) {
|
||||||
|
return R.id.bt_battery_left_summary;
|
||||||
|
}
|
||||||
|
if (deviceId == RIGHT_DEVICE_ID) {
|
||||||
|
return R.id.bt_battery_right_summary;
|
||||||
|
}
|
||||||
|
Log.d(TAG, "No resource id. The deviceId is " + deviceId);
|
||||||
|
return INVALID_RESOURCE_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideAllOfBatteryLayouts() {
|
||||||
|
// hide the case
|
||||||
|
updateBatteryLayout(R.id.bt_battery_case_title, R.id.bt_battery_case_summary,
|
||||||
|
BluetoothUtils.META_INT_ERROR);
|
||||||
|
// hide the left
|
||||||
|
updateBatteryLayout(R.id.bt_battery_left_title, R.id.bt_battery_left_summary,
|
||||||
|
BluetoothUtils.META_INT_ERROR);
|
||||||
|
// hide the right
|
||||||
|
updateBatteryLayout(R.id.bt_battery_right_title, R.id.bt_battery_right_summary,
|
||||||
|
BluetoothUtils.META_INT_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<CachedBluetoothDevice> getAllOfLeAudioDevices() {
|
||||||
|
if (mCachedDevice == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<CachedBluetoothDevice> leAudioDevices = new ArrayList<>();
|
||||||
|
leAudioDevices.add(mCachedDevice);
|
||||||
|
if (mCachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
|
||||||
|
for (CachedBluetoothDevice member : mCachedDevice.getMemberDevice()) {
|
||||||
|
leAudioDevices.add(member);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return leAudioDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBatteryLayout() {
|
||||||
|
// Init the battery layouts.
|
||||||
|
hideAllOfBatteryLayouts();
|
||||||
|
final List<CachedBluetoothDevice> leAudioDevices = getAllOfLeAudioDevices();
|
||||||
|
LeAudioProfile leAudioProfile = mProfileManager.getLeAudioProfile();
|
||||||
|
if (leAudioDevices == null || leAudioDevices.isEmpty()) {
|
||||||
|
Log.e(TAG, "There is no LeAudioProfile.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!leAudioProfile.isEnabled(mCachedDevice.getDevice())) {
|
||||||
|
Log.d(TAG, "Show the legacy battery style if the LeAudio is not enabled.");
|
||||||
|
final TextView summary = mLayoutPreference.findViewById(R.id.entity_header_summary);
|
||||||
|
if (summary != null) {
|
||||||
|
summary.setText(mCachedDevice.getConnectionSummary());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CachedBluetoothDevice cachedDevice : leAudioDevices) {
|
||||||
|
int deviceId = leAudioProfile.getAudioLocation(cachedDevice.getDevice());
|
||||||
|
Log.d(TAG, "LeAudioDevices:" + cachedDevice.getDevice().getAnonymizedAddress()
|
||||||
|
+ ", deviceId:" + deviceId);
|
||||||
|
|
||||||
|
if (deviceId == BluetoothLeAudio.AUDIO_LOCATION_INVALID) {
|
||||||
|
Log.d(TAG, "The device does not support the AUDIO_LOCATION.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean isLeft = (deviceId & LEFT_DEVICE_ID) != 0;
|
||||||
|
boolean isRight = (deviceId & LEFT_DEVICE_ID) != 0;
|
||||||
|
boolean isLeftRight = isLeft && isRight;
|
||||||
|
// The LE device updates the BatteryLayout
|
||||||
|
if (isLeftRight) {
|
||||||
|
Log.d(TAG, "The device id is left+right. Do nothing.");
|
||||||
|
} else if (isLeft) {
|
||||||
|
updateBatteryLayout(getBatteryTitleResource(LEFT_DEVICE_ID),
|
||||||
|
getBatterySummaryResource(LEFT_DEVICE_ID), cachedDevice.getBatteryLevel());
|
||||||
|
} else if (isRight) {
|
||||||
|
updateBatteryLayout(getBatteryTitleResource(RIGHT_DEVICE_ID),
|
||||||
|
getBatterySummaryResource(RIGHT_DEVICE_ID), cachedDevice.getBatteryLevel());
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "The device id is other Audio Location. Do nothing.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBatteryLayout(int titleResId, int summaryResId, int batteryLevel) {
|
||||||
|
final TextView batteryTitleView = mLayoutPreference.findViewById(titleResId);
|
||||||
|
final TextView batterySummaryView = mLayoutPreference.findViewById(summaryResId);
|
||||||
|
if (batteryTitleView == null || batterySummaryView == null) {
|
||||||
|
Log.e(TAG, "updateBatteryLayout: No TextView");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (batteryLevel != BluetoothUtils.META_INT_ERROR) {
|
||||||
|
batteryTitleView.setVisibility(View.VISIBLE);
|
||||||
|
batterySummaryView.setVisibility(View.VISIBLE);
|
||||||
|
batterySummaryView.setText(
|
||||||
|
com.android.settings.Utils.formatPercentage(batteryLevel));
|
||||||
|
batterySummaryView.setCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||||
|
createBtBatteryIcon(mContext, batteryLevel), /* top */ null,
|
||||||
|
/* end */ null, /* bottom */ null);
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "updateBatteryLayout: Hide it if it doesn't have battery information.");
|
||||||
|
batteryTitleView.setVisibility(View.GONE);
|
||||||
|
batterySummaryView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDeviceAttributesChanged() {
|
||||||
|
if (mCachedDevice != null) {
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -505,7 +505,6 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
|
|||||||
controllers.add(new HdcpCheckingPreferenceController(context));
|
controllers.add(new HdcpCheckingPreferenceController(context));
|
||||||
controllers.add(new BluetoothSnoopLogPreferenceController(context));
|
controllers.add(new BluetoothSnoopLogPreferenceController(context));
|
||||||
controllers.add(new OemUnlockPreferenceController(context, activity, fragment));
|
controllers.add(new OemUnlockPreferenceController(context, activity, fragment));
|
||||||
controllers.add(new FileEncryptionPreferenceController(context));
|
|
||||||
controllers.add(new PictureColorModePreferenceController(context, lifecycle));
|
controllers.add(new PictureColorModePreferenceController(context, lifecycle));
|
||||||
controllers.add(new WebViewAppPreferenceController(context));
|
controllers.add(new WebViewAppPreferenceController(context));
|
||||||
controllers.add(new CoolColorTemperaturePreferenceController(context));
|
controllers.add(new CoolColorTemperaturePreferenceController(context));
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.settings.development;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.os.ServiceManager;
|
|
||||||
import android.os.storage.IStorageManager;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.sysprop.CryptoProperties;
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
|
||||||
import androidx.preference.Preference;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
|
||||||
import com.android.settings.core.PreferenceControllerMixin;
|
|
||||||
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
|
|
||||||
|
|
||||||
public class FileEncryptionPreferenceController extends DeveloperOptionsPreferenceController
|
|
||||||
implements PreferenceControllerMixin {
|
|
||||||
|
|
||||||
private static final String KEY_CONVERT_FBE = "convert_to_file_encryption";
|
|
||||||
private static final String KEY_STORAGE_MANAGER = "mount";
|
|
||||||
|
|
||||||
private final IStorageManager mStorageManager;
|
|
||||||
|
|
||||||
public FileEncryptionPreferenceController(Context context) {
|
|
||||||
super(context);
|
|
||||||
|
|
||||||
mStorageManager = getStorageManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAvailable() {
|
|
||||||
if (mStorageManager == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return mStorageManager.isConvertibleToFBE();
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getPreferenceKey() {
|
|
||||||
return KEY_CONVERT_FBE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateState(Preference preference) {
|
|
||||||
if (CryptoProperties.type().orElse(CryptoProperties.type_values.NONE) !=
|
|
||||||
CryptoProperties.type_values.FILE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mPreference.setEnabled(false);
|
|
||||||
mPreference.setSummary(
|
|
||||||
mContext.getResources().getString(R.string.convert_to_file_encryption_done));
|
|
||||||
}
|
|
||||||
|
|
||||||
private IStorageManager getStorageManager() {
|
|
||||||
try {
|
|
||||||
return IStorageManager.Stub.asInterface(
|
|
||||||
ServiceManager.getService(KEY_STORAGE_MANAGER));
|
|
||||||
} catch (VerifyError e) {
|
|
||||||
// Used for tests since Robolectric cannot initialize this class.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings.deviceinfo;
|
package com.android.settings.deviceinfo;
|
||||||
|
|
||||||
|
import android.animation.TypeEvaluator;
|
||||||
|
import android.animation.ValueAnimator;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
@@ -30,6 +32,7 @@ public class StorageItemPreference extends Preference {
|
|||||||
public int userHandle;
|
public int userHandle;
|
||||||
|
|
||||||
private static final int UNINITIALIZED = -1;
|
private static final int UNINITIALIZED = -1;
|
||||||
|
private static final int ANIMATE_DURATION_IN_MILLIS = 1000;
|
||||||
|
|
||||||
private ProgressBar mProgressBar;
|
private ProgressBar mProgressBar;
|
||||||
private static final int PROGRESS_MAX = 100;
|
private static final int PROGRESS_MAX = 100;
|
||||||
@@ -46,15 +49,33 @@ public class StorageItemPreference extends Preference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setStorageSize(long size, long total) {
|
public void setStorageSize(long size, long total) {
|
||||||
mStorageSize = size;
|
setStorageSize(size, total, false /* animate */);
|
||||||
setSummary(StorageUtils.getStorageSizeLabel(getContext(), size));
|
}
|
||||||
|
|
||||||
if (total == 0) {
|
/**
|
||||||
mProgressPercent = 0;
|
* Set the storage size info with/without animation
|
||||||
|
*/
|
||||||
|
public void setStorageSize(long size, long total, boolean animate) {
|
||||||
|
if (animate) {
|
||||||
|
TypeEvaluator<Long> longEvaluator =
|
||||||
|
(fraction, startValue, endValue) -> {
|
||||||
|
// Directly returns end value if fraction is 1.0 and the end value is 0.
|
||||||
|
if (fraction >= 1.0f && endValue == 0) {
|
||||||
|
return endValue;
|
||||||
|
}
|
||||||
|
return startValue + (long) (fraction * (endValue - startValue));
|
||||||
|
};
|
||||||
|
ValueAnimator valueAnimator = ValueAnimator.ofObject(longEvaluator, mStorageSize, size);
|
||||||
|
valueAnimator.setDuration(ANIMATE_DURATION_IN_MILLIS);
|
||||||
|
valueAnimator.addUpdateListener(
|
||||||
|
animation -> {
|
||||||
|
updateProgressBarAndSizeInfo((long) animation.getAnimatedValue(), total);
|
||||||
|
});
|
||||||
|
valueAnimator.start();
|
||||||
} else {
|
} else {
|
||||||
mProgressPercent = (int)(size * PROGRESS_MAX / total);
|
updateProgressBarAndSizeInfo(size, total);
|
||||||
}
|
}
|
||||||
updateProgressBar();
|
mStorageSize = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getStorageSize() {
|
public long getStorageSize() {
|
||||||
@@ -62,11 +83,18 @@ public class StorageItemPreference extends Preference {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void updateProgressBar() {
|
protected void updateProgressBar() {
|
||||||
if (mProgressBar == null || mProgressPercent == UNINITIALIZED)
|
if (mProgressBar == null || mProgressPercent == UNINITIALIZED) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mProgressBar.setMax(PROGRESS_MAX);
|
mProgressBar.setMax(PROGRESS_MAX);
|
||||||
mProgressBar.setProgress(mProgressPercent, true /* animate */);
|
mProgressBar.setProgress(mProgressPercent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateProgressBarAndSizeInfo(long size, long total) {
|
||||||
|
setSummary(StorageUtils.getStorageSizeLabel(getContext(), size));
|
||||||
|
mProgressPercent = total == 0 ? 0 : (int) (size * PROGRESS_MAX / total);
|
||||||
|
updateProgressBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -378,18 +378,22 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
|
|||||||
*/
|
*/
|
||||||
public void onLoadFinished(@Nullable SparseArray<StorageAsyncLoader.StorageResult> result,
|
public void onLoadFinished(@Nullable SparseArray<StorageAsyncLoader.StorageResult> result,
|
||||||
int userId) {
|
int userId) {
|
||||||
|
// Enable animation when the storage size info is from StorageAsyncLoader whereas disable
|
||||||
|
// animation when the cached storage size info is used instead.
|
||||||
|
boolean animate = result != null && mIsPreferenceOrderedBySize;
|
||||||
// Calculate the size info for each category
|
// Calculate the size info for each category
|
||||||
StorageCacheHelper.StorageCache storageCache = getSizeInfo(result, userId);
|
StorageCacheHelper.StorageCache storageCache = getSizeInfo(result, userId);
|
||||||
// Set size info to each preference
|
// Set size info to each preference
|
||||||
mImagesPreference.setStorageSize(storageCache.imagesSize, mTotalSize);
|
mImagesPreference.setStorageSize(storageCache.imagesSize, mTotalSize, animate);
|
||||||
mVideosPreference.setStorageSize(storageCache.videosSize, mTotalSize);
|
mVideosPreference.setStorageSize(storageCache.videosSize, mTotalSize, animate);
|
||||||
mAudioPreference.setStorageSize(storageCache.audioSize, mTotalSize);
|
mAudioPreference.setStorageSize(storageCache.audioSize, mTotalSize, animate);
|
||||||
mAppsPreference.setStorageSize(storageCache.allAppsExceptGamesSize, mTotalSize);
|
mAppsPreference.setStorageSize(storageCache.allAppsExceptGamesSize, mTotalSize, animate);
|
||||||
mGamesPreference.setStorageSize(storageCache.gamesSize, mTotalSize);
|
mGamesPreference.setStorageSize(storageCache.gamesSize, mTotalSize, animate);
|
||||||
mDocumentsAndOtherPreference.setStorageSize(storageCache.documentsAndOtherSize, mTotalSize);
|
mDocumentsAndOtherPreference.setStorageSize(storageCache.documentsAndOtherSize, mTotalSize,
|
||||||
mTrashPreference.setStorageSize(storageCache.trashSize, mTotalSize);
|
animate);
|
||||||
|
mTrashPreference.setStorageSize(storageCache.trashSize, mTotalSize, animate);
|
||||||
if (mSystemPreference != null) {
|
if (mSystemPreference != null) {
|
||||||
mSystemPreference.setStorageSize(storageCache.systemSize, mTotalSize);
|
mSystemPreference.setStorageSize(storageCache.systemSize, mTotalSize, animate);
|
||||||
}
|
}
|
||||||
// Cache the size info
|
// Cache the size info
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@@ -519,7 +523,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
|
|||||||
if (mTrashPreference == null) {
|
if (mTrashPreference == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mTrashPreference.setStorageSize(0, mTotalSize);
|
mTrashPreference.setStorageSize(0, mTotalSize, true /* animate */);
|
||||||
updatePrivateStorageCategoryPreferencesOrder();
|
updatePrivateStorageCategoryPreferencesOrder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -182,6 +182,8 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
|||||||
showSuggestionFragment(scrollNeeded);
|
showSuggestionFragment(scrollNeeded);
|
||||||
if (FeatureFlagUtils.isEnabled(this, FeatureFlags.CONTEXTUAL_HOME)) {
|
if (FeatureFlagUtils.isEnabled(this, FeatureFlags.CONTEXTUAL_HOME)) {
|
||||||
showFragment(() -> new ContextualCardsFragment(), R.id.contextual_cards_content);
|
showFragment(() -> new ContextualCardsFragment(), R.id.contextual_cards_content);
|
||||||
|
((FrameLayout) findViewById(R.id.main_content))
|
||||||
|
.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mMainFragment = showFragment(() -> {
|
mMainFragment = showFragment(() -> {
|
||||||
@@ -191,9 +193,6 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
|||||||
return fragment;
|
return fragment;
|
||||||
}, R.id.main_content);
|
}, R.id.main_content);
|
||||||
|
|
||||||
((FrameLayout) findViewById(R.id.main_content))
|
|
||||||
.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
|
|
||||||
|
|
||||||
// Launch the intent from deep link for large screen devices.
|
// Launch the intent from deep link for large screen devices.
|
||||||
launchDeepLinkIntentToRight();
|
launchDeepLinkIntentToRight();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import android.os.Parcelable;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.preference.PreferenceScreen;
|
import androidx.preference.PreferenceScreen;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
@@ -43,14 +42,17 @@ public class TopLevelHighlightMixin implements Parcelable, DialogInterface.OnSho
|
|||||||
private String mHiddenKey;
|
private String mHiddenKey;
|
||||||
private DialogInterface mDialog;
|
private DialogInterface mDialog;
|
||||||
private HighlightableTopLevelPreferenceAdapter mTopLevelAdapter;
|
private HighlightableTopLevelPreferenceAdapter mTopLevelAdapter;
|
||||||
|
private boolean mActivityEmbedded;
|
||||||
|
|
||||||
public TopLevelHighlightMixin() {
|
public TopLevelHighlightMixin(boolean activityEmbedded) {
|
||||||
|
mActivityEmbedded = activityEmbedded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TopLevelHighlightMixin(Parcel source) {
|
public TopLevelHighlightMixin(Parcel source) {
|
||||||
mCurrentKey = source.readString();
|
mCurrentKey = source.readString();
|
||||||
mPreviousKey = source.readString();
|
mPreviousKey = source.readString();
|
||||||
mHiddenKey = source.readString();
|
mHiddenKey = source.readString();
|
||||||
|
mActivityEmbedded = source.readBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -58,6 +60,7 @@ public class TopLevelHighlightMixin implements Parcelable, DialogInterface.OnSho
|
|||||||
dest.writeString(mCurrentKey);
|
dest.writeString(mCurrentKey);
|
||||||
dest.writeString(mPreviousKey);
|
dest.writeString(mPreviousKey);
|
||||||
dest.writeString(mHiddenKey);
|
dest.writeString(mHiddenKey);
|
||||||
|
dest.writeBoolean(mActivityEmbedded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -96,8 +99,16 @@ public class TopLevelHighlightMixin implements Parcelable, DialogInterface.OnSho
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setActivityEmbedded(boolean activityEmbedded) {
|
||||||
|
mActivityEmbedded = activityEmbedded;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isActivityEmbedded() {
|
||||||
|
return mActivityEmbedded;
|
||||||
|
}
|
||||||
|
|
||||||
RecyclerView.Adapter onCreateAdapter(TopLevelSettings topLevelSettings,
|
RecyclerView.Adapter onCreateAdapter(TopLevelSettings topLevelSettings,
|
||||||
PreferenceScreen preferenceScreen) {
|
PreferenceScreen preferenceScreen, boolean scrollNeeded) {
|
||||||
if (TextUtils.isEmpty(mCurrentKey)) {
|
if (TextUtils.isEmpty(mCurrentKey)) {
|
||||||
mCurrentKey = getHighlightPrefKeyFromArguments(topLevelSettings.getArguments());
|
mCurrentKey = getHighlightPrefKeyFromArguments(topLevelSettings.getArguments());
|
||||||
}
|
}
|
||||||
@@ -105,7 +116,7 @@ public class TopLevelHighlightMixin implements Parcelable, DialogInterface.OnSho
|
|||||||
Log.d(TAG, "onCreateAdapter, pref key: " + mCurrentKey);
|
Log.d(TAG, "onCreateAdapter, pref key: " + mCurrentKey);
|
||||||
mTopLevelAdapter = new HighlightableTopLevelPreferenceAdapter(
|
mTopLevelAdapter = new HighlightableTopLevelPreferenceAdapter(
|
||||||
(SettingsHomepageActivity) topLevelSettings.getActivity(), preferenceScreen,
|
(SettingsHomepageActivity) topLevelSettings.getActivity(), preferenceScreen,
|
||||||
topLevelSettings.getListView(), mCurrentKey);
|
topLevelSettings.getListView(), mCurrentKey, scrollNeeded);
|
||||||
return mTopLevelAdapter;
|
return mTopLevelAdapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +140,7 @@ public class TopLevelHighlightMixin implements Parcelable, DialogInterface.OnSho
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void highlightPreferenceIfNeeded(FragmentActivity activity) {
|
void highlightPreferenceIfNeeded() {
|
||||||
if (mTopLevelAdapter != null) {
|
if (mTopLevelAdapter != null) {
|
||||||
mTopLevelAdapter.requestHighlight();
|
mTopLevelAdapter.requestHighlight();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ public class TopLevelSettings extends DashboardFragment implements
|
|||||||
|
|
||||||
private boolean mIsEmbeddingActivityEnabled;
|
private boolean mIsEmbeddingActivityEnabled;
|
||||||
private TopLevelHighlightMixin mHighlightMixin;
|
private TopLevelHighlightMixin mHighlightMixin;
|
||||||
|
private boolean mScrollNeeded = true;
|
||||||
private boolean mFirstStarted = true;
|
private boolean mFirstStarted = true;
|
||||||
|
|
||||||
public TopLevelSettings() {
|
public TopLevelSettings() {
|
||||||
@@ -133,11 +134,14 @@ public class TopLevelSettings extends DashboardFragment implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean activityEmbedded = SplitController.getInstance().isActivityEmbedded(getActivity());
|
||||||
if (icicle != null) {
|
if (icicle != null) {
|
||||||
mHighlightMixin = icicle.getParcelable(SAVED_HIGHLIGHT_MIXIN);
|
mHighlightMixin = icicle.getParcelable(SAVED_HIGHLIGHT_MIXIN);
|
||||||
|
mScrollNeeded = !mHighlightMixin.isActivityEmbedded() && activityEmbedded;
|
||||||
|
mHighlightMixin.setActivityEmbedded(activityEmbedded);
|
||||||
}
|
}
|
||||||
if (mHighlightMixin == null) {
|
if (mHighlightMixin == null) {
|
||||||
mHighlightMixin = new TopLevelHighlightMixin();
|
mHighlightMixin = new TopLevelHighlightMixin(activityEmbedded);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +205,7 @@ public class TopLevelSettings extends DashboardFragment implements
|
|||||||
@Override
|
@Override
|
||||||
public void highlightPreferenceIfNeeded() {
|
public void highlightPreferenceIfNeeded() {
|
||||||
if (mHighlightMixin != null) {
|
if (mHighlightMixin != null) {
|
||||||
mHighlightMixin.highlightPreferenceIfNeeded(getActivity());
|
mHighlightMixin.highlightPreferenceIfNeeded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,7 +247,7 @@ public class TopLevelSettings extends DashboardFragment implements
|
|||||||
if (!mIsEmbeddingActivityEnabled || !(getActivity() instanceof SettingsHomepageActivity)) {
|
if (!mIsEmbeddingActivityEnabled || !(getActivity() instanceof SettingsHomepageActivity)) {
|
||||||
return super.onCreateAdapter(preferenceScreen);
|
return super.onCreateAdapter(preferenceScreen);
|
||||||
}
|
}
|
||||||
return mHighlightMixin.onCreateAdapter(this, preferenceScreen);
|
return mHighlightMixin.onCreateAdapter(this, preferenceScreen, mScrollNeeded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -251,6 +251,10 @@ public class EnabledNetworkModePreferenceController extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setPreferenceEntries() {
|
void setPreferenceEntries() {
|
||||||
|
mTelephonyManager = mTelephonyManager.createForSubscriptionId(mSubId);
|
||||||
|
final PersistableBundle carrierConfig = mCarrierConfigCache.getConfigForSubId(mSubId);
|
||||||
|
final boolean display2gOptions = carrierConfig
|
||||||
|
.getBoolean(CarrierConfigManager.KEY_PREFER_2G_BOOL);
|
||||||
clearAllEntries();
|
clearAllEntries();
|
||||||
String[] entryValues;
|
String[] entryValues;
|
||||||
int[] entryValuesInt;
|
int[] entryValuesInt;
|
||||||
@@ -266,7 +270,9 @@ public class EnabledNetworkModePreferenceController extends
|
|||||||
add5gEntry(addNrToLteNetworkType(entryValuesInt[0]));
|
add5gEntry(addNrToLteNetworkType(entryValuesInt[0]));
|
||||||
addLteEntry(entryValuesInt[0]);
|
addLteEntry(entryValuesInt[0]);
|
||||||
add3gEntry(entryValuesInt[1]);
|
add3gEntry(entryValuesInt[1]);
|
||||||
add1xEntry(entryValuesInt[2]);
|
if (display2gOptions) {
|
||||||
|
add1xEntry(entryValuesInt[2]);
|
||||||
|
}
|
||||||
addGlobalEntry(entryValuesInt[3]);
|
addGlobalEntry(entryValuesInt[3]);
|
||||||
break;
|
break;
|
||||||
case ENABLED_NETWORKS_CDMA_NO_LTE_CHOICES:
|
case ENABLED_NETWORKS_CDMA_NO_LTE_CHOICES:
|
||||||
@@ -278,7 +284,9 @@ public class EnabledNetworkModePreferenceController extends
|
|||||||
"ENABLED_NETWORKS_CDMA_NO_LTE_CHOICES index error.");
|
"ENABLED_NETWORKS_CDMA_NO_LTE_CHOICES index error.");
|
||||||
}
|
}
|
||||||
add3gEntry(entryValuesInt[0]);
|
add3gEntry(entryValuesInt[0]);
|
||||||
add1xEntry(entryValuesInt[1]);
|
if (display2gOptions) {
|
||||||
|
add1xEntry(entryValuesInt[1]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ENABLED_NETWORKS_CDMA_ONLY_LTE_CHOICES:
|
case ENABLED_NETWORKS_CDMA_ONLY_LTE_CHOICES:
|
||||||
entryValues = getResourcesForSubId().getStringArray(
|
entryValues = getResourcesForSubId().getStringArray(
|
||||||
@@ -302,7 +310,9 @@ public class EnabledNetworkModePreferenceController extends
|
|||||||
add5gEntry(addNrToLteNetworkType(entryValuesInt[0]));
|
add5gEntry(addNrToLteNetworkType(entryValuesInt[0]));
|
||||||
addLteEntry(entryValuesInt[0]);
|
addLteEntry(entryValuesInt[0]);
|
||||||
add3gEntry(entryValuesInt[1]);
|
add3gEntry(entryValuesInt[1]);
|
||||||
add2gEntry(entryValuesInt[2]);
|
if (display2gOptions) {
|
||||||
|
add2gEntry(entryValuesInt[2]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ENABLED_NETWORKS_EXCEPT_GSM_LTE_CHOICES:
|
case ENABLED_NETWORKS_EXCEPT_GSM_LTE_CHOICES:
|
||||||
entryValues = getResourcesForSubId().getStringArray(
|
entryValues = getResourcesForSubId().getStringArray(
|
||||||
@@ -347,7 +357,9 @@ public class EnabledNetworkModePreferenceController extends
|
|||||||
"ENABLED_NETWORKS_EXCEPT_LTE_CHOICES index error.");
|
"ENABLED_NETWORKS_EXCEPT_LTE_CHOICES index error.");
|
||||||
}
|
}
|
||||||
add3gEntry(entryValuesInt[0]);
|
add3gEntry(entryValuesInt[0]);
|
||||||
add2gEntry(entryValuesInt[1]);
|
if (carrierConfig.getBoolean(CarrierConfigManager.KEY_PREFER_2G_BOOL)) {
|
||||||
|
add2gEntry(entryValuesInt[1]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ENABLED_NETWORKS_4G_CHOICES:
|
case ENABLED_NETWORKS_4G_CHOICES:
|
||||||
entryValues = getResourcesForSubId().getStringArray(
|
entryValues = getResourcesForSubId().getStringArray(
|
||||||
@@ -361,7 +373,9 @@ public class EnabledNetworkModePreferenceController extends
|
|||||||
entryValuesInt[0]));
|
entryValuesInt[0]));
|
||||||
add4gEntry(entryValuesInt[0]);
|
add4gEntry(entryValuesInt[0]);
|
||||||
add3gEntry(entryValuesInt[1]);
|
add3gEntry(entryValuesInt[1]);
|
||||||
add2gEntry(entryValuesInt[2]);
|
if (display2gOptions) {
|
||||||
|
add2gEntry(entryValuesInt[2]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ENABLED_NETWORKS_CHOICES:
|
case ENABLED_NETWORKS_CHOICES:
|
||||||
entryValues = getResourcesForSubId().getStringArray(
|
entryValues = getResourcesForSubId().getStringArray(
|
||||||
@@ -373,7 +387,9 @@ public class EnabledNetworkModePreferenceController extends
|
|||||||
add5gEntry(addNrToLteNetworkType(entryValuesInt[0]));
|
add5gEntry(addNrToLteNetworkType(entryValuesInt[0]));
|
||||||
addLteEntry(entryValuesInt[0]);
|
addLteEntry(entryValuesInt[0]);
|
||||||
add3gEntry(entryValuesInt[1]);
|
add3gEntry(entryValuesInt[1]);
|
||||||
add2gEntry(entryValuesInt[2]);
|
if (display2gOptions) {
|
||||||
|
add2gEntry(entryValuesInt[2]);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case PREFERRED_NETWORK_MODE_CHOICES_WORLD_MODE:
|
case PREFERRED_NETWORK_MODE_CHOICES_WORLD_MODE:
|
||||||
entryValues = getResourcesForSubId().getStringArray(
|
entryValues = getResourcesForSubId().getStringArray(
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import android.app.settings.SettingsEnums;
|
|||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.safetycenter.SafetyCenterManager;
|
||||||
import android.safetycenter.SafetyEvent;
|
import android.safetycenter.SafetyEvent;
|
||||||
|
|
||||||
import com.android.settings.security.ScreenLockPreferenceDetailsUtils;
|
import com.android.settings.security.ScreenLockPreferenceDetailsUtils;
|
||||||
@@ -37,8 +38,6 @@ import java.util.List;
|
|||||||
/** Broadcast receiver for handling requests from Safety Center for fresh data. */
|
/** Broadcast receiver for handling requests from Safety Center for fresh data. */
|
||||||
public class SafetySourceBroadcastReceiver extends BroadcastReceiver {
|
public class SafetySourceBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
private static final SafetyEvent EVENT_REFRESH_REQUESTED =
|
|
||||||
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED).build();
|
|
||||||
private static final SafetyEvent EVENT_DEVICE_REBOOTED =
|
private static final SafetyEvent EVENT_DEVICE_REBOOTED =
|
||||||
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build();
|
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build();
|
||||||
|
|
||||||
@@ -52,10 +51,15 @@ public class SafetySourceBroadcastReceiver extends BroadcastReceiver {
|
|||||||
String[] sourceIdsExtra =
|
String[] sourceIdsExtra =
|
||||||
intent.getStringArrayExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS);
|
intent.getStringArrayExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS);
|
||||||
if (sourceIdsExtra != null && sourceIdsExtra.length > 0) {
|
if (sourceIdsExtra != null && sourceIdsExtra.length > 0) {
|
||||||
|
final String refreshBroadcastId = intent.getStringExtra(
|
||||||
|
SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID);
|
||||||
|
final SafetyEvent safetyEvent = new SafetyEvent.Builder(
|
||||||
|
SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
|
||||||
|
.setRefreshBroadcastId(refreshBroadcastId).build();
|
||||||
refreshSafetySources(
|
refreshSafetySources(
|
||||||
context,
|
context,
|
||||||
ImmutableList.copyOf(sourceIdsExtra),
|
ImmutableList.copyOf(sourceIdsExtra),
|
||||||
EVENT_REFRESH_REQUESTED);
|
safetyEvent);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,10 +67,12 @@ public class HighlightableTopLevelPreferenceAdapter extends PreferenceGroupAdapt
|
|||||||
private SparseArray<PreferenceViewHolder> mViewHolders;
|
private SparseArray<PreferenceViewHolder> mViewHolders;
|
||||||
|
|
||||||
public HighlightableTopLevelPreferenceAdapter(SettingsHomepageActivity homepageActivity,
|
public HighlightableTopLevelPreferenceAdapter(SettingsHomepageActivity homepageActivity,
|
||||||
PreferenceGroup preferenceGroup, RecyclerView recyclerView, String key) {
|
PreferenceGroup preferenceGroup, RecyclerView recyclerView, String key,
|
||||||
|
boolean scrollNeeded) {
|
||||||
super(preferenceGroup);
|
super(preferenceGroup);
|
||||||
mRecyclerView = recyclerView;
|
mRecyclerView = recyclerView;
|
||||||
mHighlightKey = key;
|
mHighlightKey = key;
|
||||||
|
mScrolled = !scrollNeeded;
|
||||||
mViewHolders = new SparseArray<>();
|
mViewHolders = new SparseArray<>();
|
||||||
mContext = preferenceGroup.getContext();
|
mContext = preferenceGroup.getContext();
|
||||||
mHomepageActivity = homepageActivity;
|
mHomepageActivity = homepageActivity;
|
||||||
|
|||||||
@@ -168,10 +168,18 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS:
|
case MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS:
|
||||||
|
final Context context = getContext();
|
||||||
|
if (context == null) {
|
||||||
|
// Context may be null if the message is received after the Activity has
|
||||||
|
// been destroyed
|
||||||
|
Log.d(TAG, "Scan success but context is null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// We may get 2 WifiConfiguration if the QR code has no password in it,
|
// We may get 2 WifiConfiguration if the QR code has no password in it,
|
||||||
// one for open network and one for enhanced open network.
|
// one for open network and one for enhanced open network.
|
||||||
final WifiManager wifiManager =
|
final WifiManager wifiManager =
|
||||||
getContext().getSystemService(WifiManager.class);
|
context.getSystemService(WifiManager.class);
|
||||||
final WifiNetworkConfig qrCodeWifiNetworkConfig =
|
final WifiNetworkConfig qrCodeWifiNetworkConfig =
|
||||||
(WifiNetworkConfig)msg.obj;
|
(WifiNetworkConfig)msg.obj;
|
||||||
final List<WifiConfiguration> qrCodeWifiConfigurations =
|
final List<WifiConfiguration> qrCodeWifiConfigurations =
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ public class QrCamera extends Handler {
|
|||||||
}
|
}
|
||||||
if (mCamera != null) {
|
if (mCamera != null) {
|
||||||
mCamera.stopPreview();
|
mCamera.stopPreview();
|
||||||
|
releaseCamera();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ com.android.settings.applications.appinfo.ExternalSourcesDetails
|
|||||||
com.android.settings.applications.appinfo.WriteSettingsDetails
|
com.android.settings.applications.appinfo.WriteSettingsDetails
|
||||||
com.android.settings.applications.AppLaunchSettings
|
com.android.settings.applications.AppLaunchSettings
|
||||||
com.android.settings.applications.AppStorageSettings
|
com.android.settings.applications.AppStorageSettings
|
||||||
com.android.settings.applications.ConfirmConvertToFbe
|
|
||||||
com.android.settings.applications.ProcessStatsDetail
|
com.android.settings.applications.ProcessStatsDetail
|
||||||
com.android.settings.applications.ProcessStatsSummary
|
com.android.settings.applications.ProcessStatsSummary
|
||||||
com.android.settings.applications.ProcessStatsUi
|
com.android.settings.applications.ProcessStatsUi
|
||||||
|
|||||||
@@ -121,4 +121,16 @@ public class AccessibilityFooterPreferenceControllerTest {
|
|||||||
assertThat(learnMoreView.getVisibility()).isEqualTo(View.GONE);
|
assertThat(learnMoreView.getVisibility()).isEqualTo(View.GONE);
|
||||||
assertThat(mPreference.isLinkEnabled()).isFalse();
|
assertThat(mPreference.isLinkEnabled()).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBindViewHolder_setHelpResource_expectSummaryViewIsNonFocusable() {
|
||||||
|
mController.setupHelpLink(R.string.help_url_timeout, TEST_CONTENT_DESCRIPTION);
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
|
|
||||||
|
mPreference.onBindViewHolder(mPreferenceViewHolder);
|
||||||
|
|
||||||
|
final TextView summaryView = (TextView) mPreferenceViewHolder
|
||||||
|
.findViewById(android.R.id.title);
|
||||||
|
assertThat(summaryView.isFocusable()).isFalse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,4 +71,15 @@ public final class AccessibilityFooterPreferenceTest {
|
|||||||
android.R.id.title);
|
android.R.id.title);
|
||||||
assertThat(summaryView.getMovementMethod()).isInstanceOf(MovementMethod.class);
|
assertThat(summaryView.getMovementMethod()).isInstanceOf(MovementMethod.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onBindViewHolder_setLinkEnabled_expectSummaryViewIsNonFocusable() {
|
||||||
|
mAccessibilityFooterPreference.setLinkEnabled(true);
|
||||||
|
|
||||||
|
mAccessibilityFooterPreference.onBindViewHolder(mPreferenceViewHolder);
|
||||||
|
|
||||||
|
final TextView summaryView = (TextView) mPreferenceViewHolder.findViewById(
|
||||||
|
android.R.id.title);
|
||||||
|
assertThat(summaryView.isFocusable()).isFalse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ public class ToggleFeaturePreferenceFragmentTest {
|
|||||||
(AccessibilityFooterPreference) mFragment.getPreferenceScreen().getPreference(
|
(AccessibilityFooterPreference) mFragment.getPreferenceScreen().getPreference(
|
||||||
mFragment.getPreferenceScreen().getPreferenceCount() - 1);
|
mFragment.getPreferenceScreen().getPreferenceCount() - 1);
|
||||||
assertThat(accessibilityFooterPreference.getSummary()).isEqualTo(DEFAULT_SUMMARY);
|
assertThat(accessibilityFooterPreference.getSummary()).isEqualTo(DEFAULT_SUMMARY);
|
||||||
assertThat(accessibilityFooterPreference.isSelectable()).isEqualTo(true);
|
assertThat(accessibilityFooterPreference.isSelectable()).isEqualTo(false);
|
||||||
assertThat(accessibilityFooterPreference.getOrder()).isEqualTo(Integer.MAX_VALUE - 1);
|
assertThat(accessibilityFooterPreference.getOrder()).isEqualTo(Integer.MAX_VALUE - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2017 The Android Open Source Project
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.android.settings.development;
|
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyBoolean;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.Mockito.never;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.os.storage.IStorageManager;
|
|
||||||
import android.sysprop.CryptoProperties;
|
|
||||||
import androidx.preference.Preference;
|
|
||||||
import androidx.preference.PreferenceScreen;
|
|
||||||
|
|
||||||
import com.android.settings.R;
|
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.Mock;
|
|
||||||
import org.mockito.MockitoAnnotations;
|
|
||||||
import org.robolectric.RobolectricTestRunner;
|
|
||||||
import org.robolectric.RuntimeEnvironment;
|
|
||||||
import org.robolectric.util.ReflectionHelpers;
|
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
|
||||||
public class FileEncryptionPreferenceControllerTest {
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private Preference mPreference;
|
|
||||||
@Mock
|
|
||||||
private PreferenceScreen mPreferenceScreen;
|
|
||||||
@Mock
|
|
||||||
private IStorageManager mStorageManager;
|
|
||||||
|
|
||||||
private Context mContext;
|
|
||||||
private FileEncryptionPreferenceController mController;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void setup() {
|
|
||||||
MockitoAnnotations.initMocks(this);
|
|
||||||
mContext = RuntimeEnvironment.application;
|
|
||||||
mController = new FileEncryptionPreferenceController(mContext);
|
|
||||||
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
|
|
||||||
.thenReturn(mPreference);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void isAvailable_storageManagerNull_shouldBeFalse() {
|
|
||||||
ReflectionHelpers.setField(mController, "mStorageManager", null);
|
|
||||||
|
|
||||||
assertThat(mController.isAvailable()).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void isAvailable_notConvertibleToFBE_shouldBeFalse() throws RemoteException {
|
|
||||||
ReflectionHelpers.setField(mController, "mStorageManager", mStorageManager);
|
|
||||||
when(mStorageManager.isConvertibleToFBE()).thenReturn(false);
|
|
||||||
|
|
||||||
assertThat(mController.isAvailable()).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void isAvailable_convertibleToFBE_shouldBeTrue() throws RemoteException {
|
|
||||||
ReflectionHelpers.setField(mController, "mStorageManager", mStorageManager);
|
|
||||||
when(mStorageManager.isConvertibleToFBE()).thenReturn(true);
|
|
||||||
|
|
||||||
assertThat(mController.isAvailable()).isTrue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void updateState_settingIsNotFile_shouldDoNothing() throws RemoteException {
|
|
||||||
ReflectionHelpers.setField(mController, "mStorageManager", mStorageManager);
|
|
||||||
when(mStorageManager.isConvertibleToFBE()).thenReturn(true);
|
|
||||||
mController.displayPreference(mPreferenceScreen);
|
|
||||||
CryptoProperties.type(CryptoProperties.type_values.NONE);
|
|
||||||
|
|
||||||
mController.updateState(mPreference);
|
|
||||||
|
|
||||||
verify(mPreference, never()).setEnabled(anyBoolean());
|
|
||||||
verify(mPreference, never()).setSummary(anyString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void updateState_settingIsFile_shouldSetSummaryAndDisablePreference()
|
|
||||||
throws RemoteException {
|
|
||||||
ReflectionHelpers.setField(mController, "mStorageManager", mStorageManager);
|
|
||||||
when(mStorageManager.isConvertibleToFBE()).thenReturn(true);
|
|
||||||
mController.displayPreference(mPreferenceScreen);
|
|
||||||
CryptoProperties.type(CryptoProperties.type_values.FILE);
|
|
||||||
|
|
||||||
mController.updateState(mPreference);
|
|
||||||
|
|
||||||
verify(mPreference).setEnabled(false);
|
|
||||||
verify(mPreference).setSummary(mContext.getString(R.string.convert_to_file_encryption_done));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,8 +19,11 @@ package com.android.settings.accessibility;
|
|||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Looper;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
import androidx.preference.SwitchPreference;
|
import androidx.preference.SwitchPreference;
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
@@ -37,6 +40,7 @@ import org.junit.runner.RunWith;
|
|||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class HighTextContrastPreferenceControllerTest {
|
public class HighTextContrastPreferenceControllerTest {
|
||||||
|
|
||||||
|
private static final String PREF_KEY = "text_contrast";
|
||||||
private static final int ON = 1;
|
private static final int ON = 1;
|
||||||
private static final int OFF = 0;
|
private static final int OFF = 0;
|
||||||
private static final int UNKNOWN = -1;
|
private static final int UNKNOWN = -1;
|
||||||
@@ -44,12 +48,20 @@ public class HighTextContrastPreferenceControllerTest {
|
|||||||
private Context mContext;
|
private Context mContext;
|
||||||
private SwitchPreference mPreference;
|
private SwitchPreference mPreference;
|
||||||
private HighTextContrastPreferenceController mController;
|
private HighTextContrastPreferenceController mController;
|
||||||
|
private PreferenceScreen mScreen;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
mContext = ApplicationProvider.getApplicationContext();
|
mContext = ApplicationProvider.getApplicationContext();
|
||||||
|
if (Looper.myLooper() == null) {
|
||||||
|
Looper.prepare();
|
||||||
|
}
|
||||||
|
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
|
||||||
|
mScreen = preferenceManager.createPreferenceScreen(mContext);
|
||||||
mPreference = new SwitchPreference(mContext);
|
mPreference = new SwitchPreference(mContext);
|
||||||
mController = new HighTextContrastPreferenceController(mContext, "text_contrast");
|
mPreference.setKey(PREF_KEY);
|
||||||
|
mScreen.addPreference(mPreference);
|
||||||
|
mController = new HighTextContrastPreferenceController(mContext, PREF_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -99,10 +111,13 @@ public class HighTextContrastPreferenceControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void resetState_shouldDisableTextContrast() {
|
public void resetState_shouldDisableTextContrast() {
|
||||||
|
mController.displayPreference(mScreen);
|
||||||
mController.setChecked(true);
|
mController.setChecked(true);
|
||||||
|
mPreference.setChecked(true);
|
||||||
|
|
||||||
mController.resetState();
|
mController.resetState();
|
||||||
|
|
||||||
|
assertThat(mPreference.isChecked()).isFalse();
|
||||||
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
|
||||||
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, UNKNOWN)).isEqualTo(OFF);
|
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, UNKNOWN)).isEqualTo(OFF);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.settings.safetycenter;
|
package com.android.settings.safetycenter;
|
||||||
|
|
||||||
import static android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES;
|
import static android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES;
|
||||||
|
import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID;
|
||||||
import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCE_IDS;
|
import static android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCE_IDS;
|
||||||
import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED;
|
import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED;
|
||||||
import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED;
|
import static android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED;
|
||||||
@@ -147,6 +148,29 @@ public class SafetySourceBroadcastReceiverTest {
|
|||||||
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED).build());
|
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onReceive_onRefreshWithBroadcastId_setsRefreshEventWithBroadcastId() {
|
||||||
|
final String refreshBroadcastId = "REFRESH_BROADCAST_ID";
|
||||||
|
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||||
|
Intent intent =
|
||||||
|
new Intent()
|
||||||
|
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
||||||
|
.putExtra(
|
||||||
|
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
|
||||||
|
new String[]{ LockScreenSafetySource.SAFETY_SOURCE_ID })
|
||||||
|
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, refreshBroadcastId);
|
||||||
|
|
||||||
|
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||||
|
ArgumentCaptor<SafetyEvent> captor = ArgumentCaptor.forClass(SafetyEvent.class);
|
||||||
|
verify(mSafetyCenterManagerWrapper, times(1))
|
||||||
|
.setSafetySourceData(any(), any(), any(), captor.capture());
|
||||||
|
|
||||||
|
assertThat(captor.getValue().getRefreshBroadcastId()).isEqualTo(refreshBroadcastId);
|
||||||
|
assertThat(captor.getValue()).isEqualTo(
|
||||||
|
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
|
||||||
|
.setRefreshBroadcastId(refreshBroadcastId).build());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onReceive_onRefresh_withLockscreenSourceId_setsLockscreenData() {
|
public void onReceive_onRefresh_withLockscreenSourceId_setsLockscreenData() {
|
||||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||||
|
|||||||
Reference in New Issue
Block a user