Snap for 8590907 from 36693d8096 to tm-release
Change-Id: I6f4a4d6bcffef25a6b3371df9c093e3caae09a40
This commit is contained in:
@@ -4474,6 +4474,16 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name="com.android.settings.bluetooth.QrCodeScanModeActivity"
|
||||||
|
android:permission="android.permission.BLUETOOTH_CONNECT"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.settings.BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
|
||||||
<!-- This is the longest AndroidManifest.xml ever. -->
|
<!-- This is the longest AndroidManifest.xml ever. -->
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
23
res/drawable/ic_qr_code_scanner.xml
Normal file
23
res/drawable/ic_qr_code_scanner.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp"
|
||||||
|
android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M2,7V2H7V4H4V7ZM2,22V17H4V20H7V22ZM17,22V20H20V17H22V22ZM20,7V4H17V2H22V7ZM17.5,17.5H19V19H17.5ZM17.5,14.5H19V16H17.5ZM16,16H17.5V17.5H16ZM14.5,17.5H16V19H14.5ZM13,16H14.5V17.5H13ZM16,13H17.5V14.5H16ZM14.5,14.5H16V16H14.5ZM13,13H14.5V14.5H13ZM19,5V11H13V5ZM11,13V19H5V13ZM11,5V11H5V5ZM9.5,17.5V14.5H6.5V17.5ZM9.5,9.5V6.5H6.5V9.5ZM17.5,9.5V6.5H14.5V9.5Z"/>
|
||||||
|
</vector>
|
||||||
30
res/layout/qrcode_scan_mode_activity.xml
Normal file
30
res/layout/qrcode_scan_mode_activity.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<?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/root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/fragment_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
102
res/layout/qrcode_scanner_fragment.xml
Normal file
102
res/layout/qrcode_scanner_fragment.xml
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<?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"
|
||||||
|
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/sud_layout_icon_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="3"
|
||||||
|
android:layout_marginBottom="35dp">
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/sud_layout_icon"
|
||||||
|
android:src="@drawable/ic_qr_code_scanner"
|
||||||
|
android:tint="?androidprv:attr/colorAccentPrimaryVariant"
|
||||||
|
android:layout_width="@dimen/qrcode_icon_size"
|
||||||
|
android:layout_height="@dimen/qrcode_icon_size"
|
||||||
|
android:contentDescription="@null"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/sud_layout_title"
|
||||||
|
style="@style/QrCodeScanner"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:text="@string/bluetooth_find_broadcast_button_scan"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="19dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/sud_layout_subtitle"
|
||||||
|
style="@style/QrCodeScanner"
|
||||||
|
android:text="@string/bt_le_audio_scan_qr_code_scanner"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"/>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="7"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="top"
|
||||||
|
android:gravity="center"
|
||||||
|
android:clipChildren="true">
|
||||||
|
<TextureView
|
||||||
|
android:id="@+id/preview_view"
|
||||||
|
android:layout_marginStart="@dimen/qrcode_preview_margin"
|
||||||
|
android:layout_marginEnd="@dimen/qrcode_preview_margin"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/qrcode_preview_size"/>
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/error_message"
|
||||||
|
style="@style/TextAppearance.ErrorText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginStart="?attr/sudMarginStart"
|
||||||
|
android:layout_marginEnd="?attr/sudMarginEnd"
|
||||||
|
android:gravity="center"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:visibility="invisible"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
@@ -21,12 +21,6 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<com.android.settings.widget.SettingsMainSwitchBar
|
|
||||||
android:id="@+id/switch_bar"
|
|
||||||
android:title="@string/wifi_calling_main_switch_title"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_width="match_parent" />
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@android:id/tabcontent"
|
android:id="@android:id/tabcontent"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -485,4 +485,9 @@
|
|||||||
<!-- Sims/Data mobile/Calls/SMS select dialog-->
|
<!-- Sims/Data mobile/Calls/SMS select dialog-->
|
||||||
<dimen name="sims_select_margin_bottom">24dp</dimen>
|
<dimen name="sims_select_margin_bottom">24dp</dimen>
|
||||||
<dimen name="sims_select_margin_top">8dp</dimen>
|
<dimen name="sims_select_margin_top">8dp</dimen>
|
||||||
|
|
||||||
|
<!-- QR code picture size -->
|
||||||
|
<dimen name="qrcode_preview_margin">40dp</dimen>
|
||||||
|
<dimen name="qrcode_preview_radius">30dp</dimen>
|
||||||
|
<dimen name="qrcode_icon_size">27dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -518,6 +518,9 @@
|
|||||||
<!-- Description for the disclaimer of per app language. [CHAR LIMIT=NONE]-->
|
<!-- Description for the disclaimer of per app language. [CHAR LIMIT=NONE]-->
|
||||||
<string name="desc_app_locale_disclaimer">Language may differ from languages available in the app. Some apps may not support this setting.</string>
|
<string name="desc_app_locale_disclaimer">Language may differ from languages available in the app. Some apps may not support this setting.</string>
|
||||||
|
|
||||||
|
<!-- Description for introduction of the locale selection supported of app list [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="desc_app_locale_selection_supported">Only apps that support language selection are shown here.</string>
|
||||||
|
|
||||||
<!-- The title of the confirmation dialog shown when the user selects one / several languages and tries to remove them [CHAR LIMIT=60] -->
|
<!-- The title of the confirmation dialog shown when the user selects one / several languages and tries to remove them [CHAR LIMIT=60] -->
|
||||||
<plurals name="dlg_remove_locales_title">
|
<plurals name="dlg_remove_locales_title">
|
||||||
<item quantity="one">Remove selected language?</item>
|
<item quantity="one">Remove selected language?</item>
|
||||||
@@ -1297,7 +1300,10 @@
|
|||||||
<string name="security_advanced_settings_no_work_profile_settings_summary">Encryption, credentials, and more</string>
|
<string name="security_advanced_settings_no_work_profile_settings_summary">Encryption, credentials, and more</string>
|
||||||
<!-- Search keywords for the "More security settings" section in security settings. [CHAR_LIMIT=NONE] -->
|
<!-- Search keywords for the "More security settings" section in security settings. [CHAR_LIMIT=NONE] -->
|
||||||
<string name="security_advanced_settings_keywords">security, more security settings, more settings, advanced security settings</string>
|
<string name="security_advanced_settings_keywords">security, more security settings, more settings, advanced security settings</string>
|
||||||
|
<!-- Title for the section that has additional privacy settings. [CHAR LIMIT=60] -->
|
||||||
|
<string name="privacy_advanced_settings">More privacy settings</string>
|
||||||
|
<!-- Title for the section that has additional privacy settings. [CHAR LIMIT=60] -->
|
||||||
|
<string name="privacy_advanced_settings_summary">Autofill, activity controls, and more</string>
|
||||||
|
|
||||||
<!-- Text shown when "Add fingerprint" button is disabled -->
|
<!-- Text shown when "Add fingerprint" button is disabled -->
|
||||||
<string name="fingerprint_add_max">You can add up to <xliff:g id="count" example="5">%d</xliff:g> fingerprints</string>
|
<string name="fingerprint_add_max">You can add up to <xliff:g id="count" example="5">%d</xliff:g> fingerprints</string>
|
||||||
@@ -8973,6 +8979,9 @@
|
|||||||
<!-- Configure Notifications: Work profile section header [CHAR LIMIT=30] -->
|
<!-- Configure Notifications: Work profile section header [CHAR LIMIT=30] -->
|
||||||
<string name="profile_section_header">Work notifications</string>
|
<string name="profile_section_header">Work notifications</string>
|
||||||
|
|
||||||
|
<!-- Configure Notifications: Work profile section header [CHAR LIMIT=30] -->
|
||||||
|
<string name="profile_section_header_for_advanced_privacy">Work profile</string>
|
||||||
|
|
||||||
<!-- Configure Notifications: section header for prioritizer settings [CHAR LIMIT=80] -->
|
<!-- Configure Notifications: section header for prioritizer settings [CHAR LIMIT=80] -->
|
||||||
<string name="smart_notifications_title">Adaptive notifications</string>
|
<string name="smart_notifications_title">Adaptive notifications</string>
|
||||||
|
|
||||||
@@ -13649,7 +13658,9 @@
|
|||||||
<string name="default_active_sim_mobile_data">mobile data</string>
|
<string name="default_active_sim_mobile_data">mobile data</string>
|
||||||
<!-- Provider Model: Message to describe "Wi-Fi scan always available feature" when Wi-Fi is off and Wi-Fi
|
<!-- Provider Model: Message to describe "Wi-Fi scan always available feature" when Wi-Fi is off and Wi-Fi
|
||||||
scanning is on. To mark a link to bring the user to "scanning settings" screen. [CHAR LIMIT=NONE]-->
|
scanning is on. To mark a link to bring the user to "scanning settings" screen. [CHAR LIMIT=NONE]-->
|
||||||
<string name="wifi_scan_notify_message">To improve device experience, apps and services can still scan for Wi\u2011Fi networks at any time, even when Wi\u2011Fi is off. This can be used, for example, to improve location-based features and services. You can change this in Wi\u2011Fi scanning settings. <annotation id="link">Change</annotation></string>
|
<string name="wifi_scan_notify_message">To improve device experience, apps and services can still scan for Wi\u2011Fi networks at any time, even when Wi\u2011Fi is off. This can be used, for example, to improve location-based features and services. You can change this in Wi\u2011Fi scanning settings.</string>
|
||||||
|
<!-- Provider Model: Link text to bring the user to "scanning settings" screen. [CHAR LIMIT=NONE]-->
|
||||||
|
<string name="wifi_scan_change">Change</string>
|
||||||
|
|
||||||
<!-- Summary text separator for preferences including a short description
|
<!-- Summary text separator for preferences including a short description
|
||||||
(eg. "Connected / 5G"). [CHAR LIMIT=50] -->
|
(eg. "Connected / 5G"). [CHAR LIMIT=50] -->
|
||||||
@@ -14163,4 +14174,11 @@
|
|||||||
<string name="find_broadcast_password_dialog_connection_error">Can\u2019t connect. Try again.</string>
|
<string name="find_broadcast_password_dialog_connection_error">Can\u2019t connect. Try again.</string>
|
||||||
<!-- The error message of enter password dialog in bluetooth find broadcast page [CHAR LIMIT=none] -->
|
<!-- The error message of enter password dialog in bluetooth find broadcast page [CHAR LIMIT=none] -->
|
||||||
<string name="find_broadcast_password_dialog_password_error">Wrong password</string>
|
<string name="find_broadcast_password_dialog_password_error">Wrong password</string>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- [CHAR LIMIT=NONE] Le audio QR code scanner sub-title -->
|
||||||
|
<string name="bt_le_audio_scan_qr_code_scanner">To start listening, center the QR code below</string>
|
||||||
|
<!-- [CHAR LIMIT=NONE] Hint for QR code process failure -->
|
||||||
|
<string name="bt_le_audio_qr_code_is_not_valid_format">QR code isn\u0027t a valid format</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -962,4 +962,11 @@
|
|||||||
<item name="android:minWidth">0dp</item>
|
<item name="android:minWidth">0dp</item>
|
||||||
<item name="android:textAllCaps">false</item>
|
<item name="android:textAllCaps">false</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="QrCodeScanner">
|
||||||
|
<item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
|
||||||
|
<item name="android:textSize">16sp</item>
|
||||||
|
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||||
|
<item name="android:textDirection">locale</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -46,6 +46,11 @@
|
|||||||
android:key="action_buttons"
|
android:key="action_buttons"
|
||||||
settings:allowDividerBelow="true"/>
|
settings:allowDividerBelow="true"/>
|
||||||
|
|
||||||
|
<com.android.settings.slices.SlicePreference
|
||||||
|
android:key="bt_extra_control"
|
||||||
|
settings:controller="com.android.settings.slices.SlicePreferenceController"
|
||||||
|
settings:allowDividerAbove="true"/>
|
||||||
|
|
||||||
<com.android.settings.slices.SlicePreference
|
<com.android.settings.slices.SlicePreference
|
||||||
android:key="bt_device_slice"
|
android:key="bt_device_slice"
|
||||||
settings:controller="com.android.settings.slices.BlockingSlicePrefController"
|
settings:controller="com.android.settings.slices.BlockingSlicePrefController"
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:key="usage_amount">
|
android:key="usage_amount"
|
||||||
|
android:title="@string/summary_placeholder">
|
||||||
|
|
||||||
<com.android.settings.datausage.ChartDataUsagePreference
|
<com.android.settings.datausage.ChartDataUsagePreference
|
||||||
android:key="chart_data" />
|
android:key="chart_data" />
|
||||||
|
|||||||
96
res/xml/privacy_advanced_settings.xml
Normal file
96
res/xml/privacy_advanced_settings.xml
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
<?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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:key="privacy_dashboard_page"
|
||||||
|
android:title="@string/privacy_advanced_settings">
|
||||||
|
|
||||||
|
<!-- Work Policy info -->
|
||||||
|
<Preference
|
||||||
|
android:key="work_policy_info"
|
||||||
|
android:title="@string/work_policy_privacy_settings"
|
||||||
|
android:summary="@string/work_policy_privacy_settings_summary"
|
||||||
|
settings:controller="com.android.settings.privacy.WorkPolicyInfoPreferenceController"/>
|
||||||
|
|
||||||
|
<!-- Connected work and personal apps -->
|
||||||
|
<Preference
|
||||||
|
android:key="interact_across_profiles_privacy"
|
||||||
|
android:title="@string/interact_across_profiles_title"
|
||||||
|
android:fragment="com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesSettings"
|
||||||
|
settings:searchable="false"
|
||||||
|
settings:controller="com.android.settings.applications.specialaccess.interactacrossprofiles.InteractAcrossProfilesController" />
|
||||||
|
|
||||||
|
<!-- Accessibility usage -->
|
||||||
|
<Preference
|
||||||
|
android:key="privacy_accessibility_usage"
|
||||||
|
android:title="@string/accessibility_usage_title"
|
||||||
|
settings:controller="com.android.settings.privacy.AccessibilityUsagePreferenceController">
|
||||||
|
<intent android:action="android.intent.action.REVIEW_ACCESSIBILITY_SERVICES"/>
|
||||||
|
</Preference>
|
||||||
|
|
||||||
|
<!-- On lock screen notifications -->
|
||||||
|
<com.android.settings.RestrictedListPreference
|
||||||
|
android:key="privacy_lock_screen_notifications"
|
||||||
|
android:title="@string/lock_screen_notifs_title"
|
||||||
|
android:summary="@string/summary_placeholder"
|
||||||
|
settings:searchable="false"/>
|
||||||
|
|
||||||
|
<!-- Privacy Service -->
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="privacy_services"
|
||||||
|
android:layout="@layout/preference_category_no_label"/>
|
||||||
|
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="dashboard_tile_placeholder"/>
|
||||||
|
|
||||||
|
<!-- Work profile settings are at the bottom with high order value to avoid users thinking that
|
||||||
|
any of the above settings (including dynamic) are specific to the work profile. -->
|
||||||
|
<PreferenceCategory
|
||||||
|
android:key="privacy_work_profile_notifications_category"
|
||||||
|
android:title="@string/profile_section_header_for_advanced_privacy"
|
||||||
|
android:order="998">
|
||||||
|
|
||||||
|
<com.android.settings.RestrictedListPreference
|
||||||
|
android:key="privacy_lock_screen_work_profile_notifications"
|
||||||
|
android:title="@string/locked_work_profile_notification_title"
|
||||||
|
android:summary="@string/summary_placeholder"
|
||||||
|
android:order="999"
|
||||||
|
settings:searchable="false"/>
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<!-- Content Capture -->
|
||||||
|
|
||||||
|
<!-- NOTE: content capture has a different preference, depending whether or not the
|
||||||
|
ContentCaptureService implementations defines a custom settings activitiy on its manifest.
|
||||||
|
Hence, we show both here, but the controller itself will decide if it's available or not.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<SwitchPreference
|
||||||
|
android:key="content_capture"
|
||||||
|
android:title="@string/content_capture"
|
||||||
|
android:summary="@string/content_capture_summary"
|
||||||
|
settings:controller="com.android.settings.privacy.EnableContentCapturePreferenceController"/>
|
||||||
|
|
||||||
|
<com.android.settingslib.PrimarySwitchPreference
|
||||||
|
android:key="content_capture_custom_settings"
|
||||||
|
android:title="@string/content_capture"
|
||||||
|
android:summary="@string/content_capture_summary"
|
||||||
|
settings:controller="com.android.settings.privacy.EnableContentCaptureWithServiceSettingsPreferenceController"/>
|
||||||
|
|
||||||
|
</PreferenceScreen>
|
||||||
@@ -19,6 +19,10 @@
|
|||||||
android:key="wifi_calling_settings"
|
android:key="wifi_calling_settings"
|
||||||
android:title="@string/wifi_calling_settings_title">
|
android:title="@string/wifi_calling_settings_title">
|
||||||
|
|
||||||
|
<com.android.settings.widget.SettingsMainSwitchPreference
|
||||||
|
android:key="wifi_calling_switch_bar"
|
||||||
|
android:title="@string/wifi_calling_main_switch_title" />
|
||||||
|
|
||||||
<com.android.settings.wifi.calling.ListWithEntrySummaryPreference
|
<com.android.settings.wifi.calling.ListWithEntrySummaryPreference
|
||||||
android:key="wifi_calling_mode"
|
android:key="wifi_calling_mode"
|
||||||
isPreferenceVisible="false"
|
isPreferenceVisible="false"
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings;
|
package com.android.settings;
|
||||||
|
|
||||||
|
import static android.provider.Settings.ACTION_PRIVACY_SETTINGS;
|
||||||
|
|
||||||
import android.content.ActivityNotFoundException;
|
import android.content.ActivityNotFoundException;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -214,7 +216,8 @@ public class Settings extends SettingsActivity {
|
|||||||
/** Redirects to SafetyCenter if enabled. */
|
/** Redirects to SafetyCenter if enabled. */
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void handleSafetyCenterRedirection() {
|
public void handleSafetyCenterRedirection() {
|
||||||
if (SafetyCenterManagerWrapper.get().isEnabled(this)) {
|
if (ACTION_PRIVACY_SETTINGS.equals(getIntent().getAction())
|
||||||
|
&& SafetyCenterManagerWrapper.get().isEnabled(this)) {
|
||||||
try {
|
try {
|
||||||
startActivity(new Intent(Intent.ACTION_SAFETY_CENTER));
|
startActivity(new Intent(Intent.ACTION_SAFETY_CENTER));
|
||||||
finish();
|
finish();
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import android.content.SharedPreferences;
|
|||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
|
import android.content.pm.UserInfo;
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
import android.content.res.Resources.Theme;
|
import android.content.res.Resources.Theme;
|
||||||
import android.graphics.drawable.Icon;
|
import android.graphics.drawable.Icon;
|
||||||
@@ -152,6 +153,8 @@ public class SettingsActivity extends SettingsBaseActivity
|
|||||||
*/
|
*/
|
||||||
public static final String EXTRA_IS_FROM_SLICE = "is_from_slice";
|
public static final String EXTRA_IS_FROM_SLICE = "is_from_slice";
|
||||||
|
|
||||||
|
public static final String EXTRA_USER_HANDLE = "user_handle";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Personal or Work profile tab of {@link ProfileSelectFragment}
|
* Personal or Work profile tab of {@link ProfileSelectFragment}
|
||||||
* <p>0: Personal tab.
|
* <p>0: Personal tab.
|
||||||
@@ -427,7 +430,14 @@ public class SettingsActivity extends SettingsBaseActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
final UserManager um = getSystemService(UserManager.class);
|
||||||
|
final UserInfo userInfo = um.getUserInfo(getUser().getIdentifier());
|
||||||
|
if (userInfo.isManagedProfile()) {
|
||||||
|
trampolineIntent.putExtra(EXTRA_USER_HANDLE, getUser());
|
||||||
|
startActivityAsUser(trampolineIntent, um.getPrimaryUser().getUserHandle());
|
||||||
|
} else {
|
||||||
startActivity(trampolineIntent);
|
startActivity(trampolineIntent);
|
||||||
|
}
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (ActivityNotFoundException e) {
|
||||||
Log.e(LOG_TAG, "Deep link homepage is not available to show 2-pane UI");
|
Log.e(LOG_TAG, "Deep link homepage is not available to show 2-pane UI");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -27,8 +27,11 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settingslib.Utils;
|
import com.android.settingslib.Utils;
|
||||||
|
import com.android.settingslib.widget.LayoutPreference;
|
||||||
|
|
||||||
import com.google.android.setupdesign.GlifPreferenceLayout;
|
import com.google.android.setupdesign.GlifPreferenceLayout;
|
||||||
|
import com.google.android.setupdesign.util.LayoutStyler;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link androidx.preference.PreferenceFragmentCompat} that displays the settings page related
|
* A {@link androidx.preference.PreferenceFragmentCompat} that displays the settings page related
|
||||||
@@ -47,6 +50,8 @@ public class TextReadingPreferenceFragmentForSetupWizard extends TextReadingPref
|
|||||||
icon.setTintList(Utils.getColorAttr(getContext(), android.R.attr.colorPrimary));
|
icon.setTintList(Utils.getColorAttr(getContext(), android.R.attr.colorPrimary));
|
||||||
AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
|
AccessibilitySetupWizardUtils.updateGlifPreferenceLayout(getContext(), layout, title,
|
||||||
/* description= */ null, icon);
|
/* description= */ null, icon);
|
||||||
|
|
||||||
|
updateResetButtonPadding();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -66,4 +71,14 @@ public class TextReadingPreferenceFragmentForSetupWizard extends TextReadingPref
|
|||||||
// Hides help center in action bar and footer bar in SuW
|
// Hides help center in action bar and footer bar in SuW
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the padding of the reset button to meet for SetupWizard style.
|
||||||
|
*/
|
||||||
|
private void updateResetButtonPadding() {
|
||||||
|
final LayoutPreference resetPreference = (LayoutPreference) findPreference(RESET_KEY);
|
||||||
|
final ViewGroup parentView =
|
||||||
|
(ViewGroup) resetPreference.findViewById(R.id.reset_button).getParent();
|
||||||
|
LayoutStyler.applyPartnerCustomizationLayoutPaddingStyle(parentView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ public class ToggleScreenReaderPreferenceFragmentForSetupWizard
|
|||||||
if (mTopIntroPreference != null) {
|
if (mTopIntroPreference != null) {
|
||||||
mTopIntroPreference.setVisible(false);
|
mTopIntroPreference.setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mToggleServiceSwitchPreference.applyPartnerCustomizationPaddingStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -85,6 +85,14 @@ public class ApplicationViewHolder extends RecyclerView.ViewHolder {
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static View newHeader(ViewGroup parent, int resText) {
|
||||||
|
ViewGroup view = (ViewGroup) LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(R.layout.preference_app_header, parent, false);
|
||||||
|
TextView textView = view.findViewById(R.id.apps_top_intro_text);
|
||||||
|
textView.setText(resText);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
void setSummary(CharSequence summary) {
|
void setSummary(CharSequence summary) {
|
||||||
mSummary.setText(summary);
|
mSummary.setText(summary);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -824,14 +824,16 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
if (mApplications == null) {
|
if (mApplications == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final int position = mRecyclerView.getChildAdapterPosition(view);
|
final int applicationPosition =
|
||||||
|
ApplicationsAdapter.getApplicationPosition(
|
||||||
|
mListType, mRecyclerView.getChildAdapterPosition(view));
|
||||||
|
|
||||||
if (position == RecyclerView.NO_POSITION) {
|
if (applicationPosition == RecyclerView.NO_POSITION) {
|
||||||
Log.w(TAG, "Cannot find position for child, skipping onClick handling");
|
Log.w(TAG, "Cannot find position for child, skipping onClick handling");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mApplications.getApplicationCount() > position) {
|
if (mApplications.getApplicationCount() > applicationPosition) {
|
||||||
ApplicationsState.AppEntry entry = mApplications.getAppEntry(position);
|
ApplicationsState.AppEntry entry = mApplications.getAppEntry(applicationPosition);
|
||||||
mCurrentPkgName = entry.info.packageName;
|
mCurrentPkgName = entry.info.packageName;
|
||||||
mCurrentUid = entry.info.uid;
|
mCurrentUid = entry.info.uid;
|
||||||
startApplicationDetailsActivity();
|
startApplicationDetailsActivity();
|
||||||
@@ -1058,6 +1060,7 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
private static final String STATE_LAST_SCROLL_INDEX = "state_last_scroll_index";
|
private static final String STATE_LAST_SCROLL_INDEX = "state_last_scroll_index";
|
||||||
private static final int VIEW_TYPE_APP = 0;
|
private static final int VIEW_TYPE_APP = 0;
|
||||||
private static final int VIEW_TYPE_EXTRA_VIEW = 1;
|
private static final int VIEW_TYPE_EXTRA_VIEW = 1;
|
||||||
|
private static final int VIEW_TYPE_APP_HEADER = 2;
|
||||||
|
|
||||||
private final ApplicationsState mState;
|
private final ApplicationsState mState;
|
||||||
private final ApplicationsState.Session mSession;
|
private final ApplicationsState.Session mSession;
|
||||||
@@ -1229,7 +1232,11 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
@Override
|
@Override
|
||||||
public ApplicationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
public ApplicationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
final View view;
|
final View view;
|
||||||
if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {
|
if (mManageApplications.mListType == LIST_TYPE_APPS_LOCALE
|
||||||
|
&& viewType == VIEW_TYPE_APP_HEADER) {
|
||||||
|
view = ApplicationViewHolder.newHeader(parent,
|
||||||
|
R.string.desc_app_locale_selection_supported);
|
||||||
|
} else if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {
|
||||||
view = ApplicationViewHolder.newView(parent, true /* twoTarget */);
|
view = ApplicationViewHolder.newView(parent, true /* twoTarget */);
|
||||||
} else {
|
} else {
|
||||||
view = ApplicationViewHolder.newView(parent, false /* twoTarget */);
|
view = ApplicationViewHolder.newView(parent, false /* twoTarget */);
|
||||||
@@ -1239,6 +1246,9 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemViewType(int position) {
|
public int getItemViewType(int position) {
|
||||||
|
if (position == 0 && mManageApplications.mListType == LIST_TYPE_APPS_LOCALE) {
|
||||||
|
return VIEW_TYPE_APP_HEADER;
|
||||||
|
}
|
||||||
return VIEW_TYPE_APP;
|
return VIEW_TYPE_APP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1472,10 +1482,11 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemCount() {
|
public int getItemCount() {
|
||||||
if (mEntries == null) {
|
int count = getApplicationCount();
|
||||||
return 0;
|
if (count != 0 && mManageApplications.mListType == LIST_TYPE_APPS_LOCALE) {
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
return mEntries.size();
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getApplicationCount() {
|
public int getApplicationCount() {
|
||||||
@@ -1483,15 +1494,18 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
public AppEntry getAppEntry(int position) {
|
public AppEntry getAppEntry(int position) {
|
||||||
return mEntries.get(position);
|
return mEntries.get(
|
||||||
|
getApplicationPosition(mManageApplications.mListType, position));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getItemId(int position) {
|
public long getItemId(int position) {
|
||||||
if (position == mEntries.size()) {
|
int applicationPosition =
|
||||||
|
getApplicationPosition(mManageApplications.mListType, position);
|
||||||
|
if (applicationPosition == mEntries.size()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return mEntries.get(position).id;
|
return mEntries.get(applicationPosition).id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnabled(int position) {
|
public boolean isEnabled(int position) {
|
||||||
@@ -1499,7 +1513,9 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
|| mManageApplications.mListType != LIST_TYPE_HIGH_POWER) {
|
|| mManageApplications.mListType != LIST_TYPE_HIGH_POWER) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ApplicationsState.AppEntry entry = mEntries.get(position);
|
ApplicationsState.AppEntry entry =
|
||||||
|
mEntries.get(
|
||||||
|
getApplicationPosition(mManageApplications.mListType, position));
|
||||||
|
|
||||||
return !mBackend.isSysAllowlisted(entry.info.packageName)
|
return !mBackend.isSysAllowlisted(entry.info.packageName)
|
||||||
&& !mBackend.isDefaultActiveApp(entry.info.packageName);
|
&& !mBackend.isDefaultActiveApp(entry.info.packageName);
|
||||||
@@ -1507,8 +1523,15 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(ApplicationViewHolder holder, int position) {
|
public void onBindViewHolder(ApplicationViewHolder holder, int position) {
|
||||||
|
if (getItemViewType(position) == VIEW_TYPE_APP_HEADER) {
|
||||||
|
// It does not bind holder here, due to header view.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Bind the data efficiently with the holder
|
// Bind the data efficiently with the holder
|
||||||
final ApplicationsState.AppEntry entry = mEntries.get(position);
|
final ApplicationsState.AppEntry entry =
|
||||||
|
mEntries.get(
|
||||||
|
getApplicationPosition(mManageApplications.mListType, position));
|
||||||
synchronized (entry) {
|
synchronized (entry) {
|
||||||
mState.ensureLabelDescription(entry);
|
mState.ensureLabelDescription(entry);
|
||||||
holder.setTitle(entry.label, entry.labelDescription);
|
holder.setTitle(entry.label, entry.labelDescription);
|
||||||
@@ -1608,6 +1631,22 @@ public class ManageApplications extends InstrumentedFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjusts position if this list adds a header.
|
||||||
|
* TODO(b/232533002) Add a header view on adapter of RecyclerView may not a good idea since
|
||||||
|
* ManageApplication is a generic purpose. In the future, here shall look for
|
||||||
|
* a better way to add a header without using recyclerView or any other ways
|
||||||
|
* to achieve the goal.
|
||||||
|
*/
|
||||||
|
public static int getApplicationPosition(int listType, int position) {
|
||||||
|
int applicationPosition = position;
|
||||||
|
// Adjust position due to header added.
|
||||||
|
if (position > 0 && listType == LIST_TYPE_APPS_LOCALE) {
|
||||||
|
applicationPosition = position - 1;
|
||||||
|
}
|
||||||
|
return applicationPosition;
|
||||||
|
}
|
||||||
|
|
||||||
public static class OnScrollListener extends RecyclerView.OnScrollListener {
|
public static class OnScrollListener extends RecyclerView.OnScrollListener {
|
||||||
private int mScrollState = SCROLL_STATE_IDLE;
|
private int mScrollState = SCROLL_STATE_IDLE;
|
||||||
private boolean mDelayNotifyDataChange;
|
private boolean mDelayNotifyDataChange;
|
||||||
|
|||||||
@@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
package com.android.settings.bluetooth;
|
package com.android.settings.bluetooth;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothLeAudioContentMetadata;
|
||||||
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
||||||
|
import android.bluetooth.BluetoothLeBroadcastReceiveState;
|
||||||
import android.bluetooth.BluetoothLeBroadcastSubgroup;
|
import android.bluetooth.BluetoothLeBroadcastSubgroup;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@@ -43,16 +45,15 @@ class BluetoothBroadcastSourcePreference extends Preference {
|
|||||||
private static final int RESOURCE_ID_ICON = R.drawable.settings_input_antenna;
|
private static final int RESOURCE_ID_ICON = R.drawable.settings_input_antenna;
|
||||||
|
|
||||||
private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
|
private BluetoothLeBroadcastMetadata mBluetoothLeBroadcastMetadata;
|
||||||
|
private BluetoothLeBroadcastReceiveState mBluetoothLeBroadcastReceiveState;
|
||||||
private ImageView mFrictionImageView;
|
private ImageView mFrictionImageView;
|
||||||
private String mTitle;
|
private String mTitle;
|
||||||
private boolean mStatus;
|
private boolean mStatus;
|
||||||
private boolean mIsEncrypted;
|
private boolean mIsEncrypted;
|
||||||
|
|
||||||
BluetoothBroadcastSourcePreference(@NonNull Context context,
|
BluetoothBroadcastSourcePreference(@NonNull Context context) {
|
||||||
@NonNull BluetoothLeBroadcastMetadata source) {
|
|
||||||
super(context);
|
super(context);
|
||||||
initUi();
|
initUi();
|
||||||
updateMetadataAndRefreshUi(source, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -68,7 +69,7 @@ class BluetoothBroadcastSourcePreference extends Preference {
|
|||||||
private void initUi() {
|
private void initUi() {
|
||||||
setLayoutResource(R.layout.preference_access_point);
|
setLayoutResource(R.layout.preference_access_point);
|
||||||
setWidgetLayoutResource(R.layout.access_point_friction_widget);
|
setWidgetLayoutResource(R.layout.access_point_friction_widget);
|
||||||
|
mTitle = getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO);
|
||||||
mStatus = false;
|
mStatus = false;
|
||||||
final Drawable drawable = getContext().getDrawable(RESOURCE_ID_ICON);
|
final Drawable drawable = getContext().getDrawable(RESOURCE_ID_ICON);
|
||||||
if (drawable != null) {
|
if (drawable != null) {
|
||||||
@@ -105,9 +106,20 @@ class BluetoothBroadcastSourcePreference extends Preference {
|
|||||||
*/
|
*/
|
||||||
public void updateMetadataAndRefreshUi(BluetoothLeBroadcastMetadata source, boolean status) {
|
public void updateMetadataAndRefreshUi(BluetoothLeBroadcastMetadata source, boolean status) {
|
||||||
mBluetoothLeBroadcastMetadata = source;
|
mBluetoothLeBroadcastMetadata = source;
|
||||||
mTitle = getBroadcastMetadataProgramInfo();
|
mTitle = getProgramInfo();
|
||||||
mIsEncrypted = mBluetoothLeBroadcastMetadata.isEncrypted();
|
mIsEncrypted = mBluetoothLeBroadcastMetadata.isEncrypted();
|
||||||
mStatus = status;
|
mStatus = status || mBluetoothLeBroadcastReceiveState != null;
|
||||||
|
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the title and status from BluetoothLeBroadcastReceiveState.
|
||||||
|
*/
|
||||||
|
public void updateReceiveStateAndRefreshUi(BluetoothLeBroadcastReceiveState receiveState) {
|
||||||
|
mBluetoothLeBroadcastReceiveState = receiveState;
|
||||||
|
mTitle = getProgramInfo();
|
||||||
|
mStatus = true;
|
||||||
|
|
||||||
refresh();
|
refresh();
|
||||||
}
|
}
|
||||||
@@ -124,7 +136,17 @@ class BluetoothBroadcastSourcePreference extends Preference {
|
|||||||
updateStatusButton();
|
updateStatusButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getBroadcastMetadataProgramInfo() {
|
private String getProgramInfo() {
|
||||||
|
if (mBluetoothLeBroadcastReceiveState != null) {
|
||||||
|
List<BluetoothLeAudioContentMetadata> bluetoothLeAudioContentMetadata =
|
||||||
|
mBluetoothLeBroadcastReceiveState.getSubgroupMetadata();
|
||||||
|
if (!bluetoothLeAudioContentMetadata.isEmpty()) {
|
||||||
|
return bluetoothLeAudioContentMetadata.stream()
|
||||||
|
.map(i -> i.getProgramInfo())
|
||||||
|
.findFirst().orElse(
|
||||||
|
getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (mBluetoothLeBroadcastMetadata == null) {
|
if (mBluetoothLeBroadcastMetadata == null) {
|
||||||
return getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO);
|
return getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO);
|
||||||
}
|
}
|
||||||
@@ -138,4 +160,24 @@ class BluetoothBroadcastSourcePreference extends Preference {
|
|||||||
.filter(i -> !TextUtils.isEmpty(i))
|
.filter(i -> !TextUtils.isEmpty(i))
|
||||||
.findFirst().orElse(getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO));
|
.findFirst().orElse(getContext().getString(RESOURCE_ID_UNKNOWN_PROGRAM_INFO));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the broadcast source is encrypted or not.
|
||||||
|
* @return If true, the broadcast source needs the broadcast code. If false, the broadcast
|
||||||
|
* source does not need the broadcast code.
|
||||||
|
*/
|
||||||
|
public boolean isEncrypted() {
|
||||||
|
return mIsEncrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear the BluetoothLeBroadcastReceiveState and reset the state when the user clicks the
|
||||||
|
* "leave broadcast" button.
|
||||||
|
*/
|
||||||
|
public void clearReceiveState() {
|
||||||
|
mBluetoothLeBroadcastReceiveState = null;
|
||||||
|
mTitle = getProgramInfo();
|
||||||
|
mStatus = false;
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,12 +22,18 @@ import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
|
|||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.provider.DeviceConfig;
|
import android.provider.DeviceConfig;
|
||||||
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewTreeObserver;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
@@ -36,12 +42,14 @@ import com.android.settings.core.SettingsUIDeviceConfig;
|
|||||||
import com.android.settings.dashboard.RestrictedDashboardFragment;
|
import com.android.settings.dashboard.RestrictedDashboardFragment;
|
||||||
import com.android.settings.overlay.FeatureFactory;
|
import com.android.settings.overlay.FeatureFactory;
|
||||||
import com.android.settings.slices.BlockingSlicePrefController;
|
import com.android.settings.slices.BlockingSlicePrefController;
|
||||||
|
import com.android.settings.slices.SlicePreferenceController;
|
||||||
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
import com.android.settingslib.core.AbstractPreferenceController;
|
import com.android.settingslib.core.AbstractPreferenceController;
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.IllegalFormatException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment {
|
public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment {
|
||||||
@@ -61,6 +69,7 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
|
|||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
interface TestDataFactory {
|
interface TestDataFactory {
|
||||||
CachedBluetoothDevice getDevice(String deviceAddress);
|
CachedBluetoothDevice getDevice(String deviceAddress);
|
||||||
|
|
||||||
LocalBluetoothManager getManager(Context context);
|
LocalBluetoothManager getManager(Context context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +136,49 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
|
|||||||
use(BlockingSlicePrefController.class).setSliceUri(sliceEnabled
|
use(BlockingSlicePrefController.class).setSliceUri(sliceEnabled
|
||||||
? featureProvider.getBluetoothDeviceSettingsUri(mCachedDevice.getDevice())
|
? featureProvider.getBluetoothDeviceSettingsUri(mCachedDevice.getDevice())
|
||||||
: null);
|
: null);
|
||||||
|
updateExtraControlUri(/* viewWidth */ 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateExtraControlUri(int viewWidth) {
|
||||||
|
BluetoothFeatureProvider featureProvider = FeatureFactory.getFactory(
|
||||||
|
getContext()).getBluetoothFeatureProvider(getContext());
|
||||||
|
boolean sliceEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SETTINGS_UI,
|
||||||
|
SettingsUIDeviceConfig.BT_SLICE_SETTINGS_ENABLED, true);
|
||||||
|
Uri controlUri = null;
|
||||||
|
String uri = featureProvider.getBluetoothDeviceControlUri(mCachedDevice.getDevice());
|
||||||
|
if (!TextUtils.isEmpty(uri)) {
|
||||||
|
try {
|
||||||
|
controlUri = Uri.parse(String.format(uri, viewWidth));
|
||||||
|
} catch (IllegalFormatException | NullPointerException exception) {
|
||||||
|
Log.d(TAG, "unable to parse uri");
|
||||||
|
controlUri = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
use(SlicePreferenceController.class).setSliceUri(sliceEnabled ? controlUri : null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ViewTreeObserver.OnGlobalLayoutListener mOnGlobalLayoutListener =
|
||||||
|
new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||||
|
@Override
|
||||||
|
public void onGlobalLayout() {
|
||||||
|
View view = getView();
|
||||||
|
if (view == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateExtraControlUri(view.getWidth());
|
||||||
|
view.getViewTreeObserver().removeOnGlobalLayoutListener(
|
||||||
|
mOnGlobalLayoutListener);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||||
|
if (view != null) {
|
||||||
|
view.getViewTreeObserver().addOnGlobalLayoutListener(mOnGlobalLayoutListener);
|
||||||
|
}
|
||||||
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -26,8 +26,17 @@ public interface BluetoothFeatureProvider {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the {@link Uri} that represents extra settings for a specific bluetooth device
|
* Get the {@link Uri} that represents extra settings for a specific bluetooth device
|
||||||
|
*
|
||||||
* @param bluetoothDevice bluetooth device
|
* @param bluetoothDevice bluetooth device
|
||||||
* @return {@link Uri} for extra settings
|
* @return {@link Uri} for extra settings
|
||||||
*/
|
*/
|
||||||
Uri getBluetoothDeviceSettingsUri(BluetoothDevice bluetoothDevice);
|
Uri getBluetoothDeviceSettingsUri(BluetoothDevice bluetoothDevice);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link Uri} that represents extra control for a specific bluetooth device
|
||||||
|
*
|
||||||
|
* @param bluetoothDevice bluetooth device
|
||||||
|
* @return {@link String} uri string for extra control
|
||||||
|
*/
|
||||||
|
String getBluetoothDeviceControlUri(BluetoothDevice bluetoothDevice);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import android.bluetooth.BluetoothDevice;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Impl of {@link BluetoothFeatureProvider}
|
* Impl of {@link BluetoothFeatureProvider}
|
||||||
*/
|
*/
|
||||||
@@ -37,4 +39,9 @@ public class BluetoothFeatureProviderImpl implements BluetoothFeatureProvider {
|
|||||||
BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI);
|
BluetoothDevice.METADATA_ENHANCED_SETTINGS_UI_URI);
|
||||||
return uriByte == null ? null : Uri.parse(new String(uriByte));
|
return uriByte == null ? null : Uri.parse(new String(uriByte));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBluetoothDeviceControlUri(BluetoothDevice bluetoothDevice) {
|
||||||
|
return BluetoothUtils.getControlUriMetaData(bluetoothDevice);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,9 +86,7 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment
|
|||||||
@Override
|
@Override
|
||||||
public void onSearchStarted(int reason) {
|
public void onSearchStarted(int reason) {
|
||||||
Log.d(TAG, "onSearchStarted: " + reason);
|
Log.d(TAG, "onSearchStarted: " + reason);
|
||||||
|
getActivity().runOnUiThread(() -> handleSearchStarted());
|
||||||
getActivity().runOnUiThread(
|
|
||||||
() -> cacheRemoveAllPrefs(mBroadcastSourceListCategory));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -109,7 +107,8 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment
|
|||||||
@Override
|
@Override
|
||||||
public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {
|
public void onSourceFound(@NonNull BluetoothLeBroadcastMetadata source) {
|
||||||
Log.d(TAG, "onSourceFound:");
|
Log.d(TAG, "onSourceFound:");
|
||||||
getActivity().runOnUiThread(() -> updateListCategory(source, false));
|
getActivity().runOnUiThread(
|
||||||
|
() -> updateListCategoryFromBroadcastMetadata(source, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -119,7 +118,7 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment
|
|||||||
Log.w(TAG, "onSourceAdded: mSelectedPreference == null!");
|
Log.w(TAG, "onSourceAdded: mSelectedPreference == null!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
getActivity().runOnUiThread(() -> updateListCategory(
|
getActivity().runOnUiThread(() -> updateListCategoryFromBroadcastMetadata(
|
||||||
mSelectedPreference.getBluetoothLeBroadcastMetadata(), true));
|
mSelectedPreference.getBluetoothLeBroadcastMetadata(), true));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,6 +143,7 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment
|
|||||||
public void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId,
|
public void onSourceRemoved(@NonNull BluetoothDevice sink, int sourceId,
|
||||||
int reason) {
|
int reason) {
|
||||||
Log.d(TAG, "onSourceRemoved:");
|
Log.d(TAG, "onSourceRemoved:");
|
||||||
|
getActivity().runOnUiThread(() -> handleSourceRemoved());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -215,6 +215,8 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment
|
|||||||
//check assistant status. Start searching...
|
//check assistant status. Start searching...
|
||||||
if (mLeBroadcastAssistant != null && !mLeBroadcastAssistant.isSearchInProgress()) {
|
if (mLeBroadcastAssistant != null && !mLeBroadcastAssistant.isSearchInProgress()) {
|
||||||
mLeBroadcastAssistant.startSearchingForSources(getScanFilter());
|
mLeBroadcastAssistant.startSearchingForSources(getScanFilter());
|
||||||
|
} else {
|
||||||
|
addConnectedSourcePreference();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,11 +312,13 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateListCategory(BluetoothLeBroadcastMetadata source, boolean isConnected) {
|
private void updateListCategoryFromBroadcastMetadata(BluetoothLeBroadcastMetadata source,
|
||||||
|
boolean isConnected) {
|
||||||
BluetoothBroadcastSourcePreference item = mBroadcastSourceListCategory.findPreference(
|
BluetoothBroadcastSourcePreference item = mBroadcastSourceListCategory.findPreference(
|
||||||
Integer.toString(source.getBroadcastId()));
|
Integer.toString(source.getBroadcastId()));
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
item = createBluetoothBroadcastSourcePreference(source);
|
item = createBluetoothBroadcastSourcePreference();
|
||||||
|
item.setKey(Integer.toString(source.getBroadcastId()));
|
||||||
mBroadcastSourceListCategory.addPreference(item);
|
mBroadcastSourceListCategory.addPreference(item);
|
||||||
}
|
}
|
||||||
item.updateMetadataAndRefreshUi(source, isConnected);
|
item.updateMetadataAndRefreshUi(source, isConnected);
|
||||||
@@ -326,13 +330,36 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BluetoothBroadcastSourcePreference createBluetoothBroadcastSourcePreference(
|
private void updateListCategoryFromBroadcastReceiveState(
|
||||||
BluetoothLeBroadcastMetadata source) {
|
BluetoothLeBroadcastReceiveState receiveState) {
|
||||||
|
BluetoothBroadcastSourcePreference item = mBroadcastSourceListCategory.findPreference(
|
||||||
|
Integer.toString(receiveState.getBroadcastId()));
|
||||||
|
if (item == null) {
|
||||||
|
item = createBluetoothBroadcastSourcePreference();
|
||||||
|
item.setKey(Integer.toString(receiveState.getBroadcastId()));
|
||||||
|
mBroadcastSourceListCategory.addPreference(item);
|
||||||
|
}
|
||||||
|
item.updateReceiveStateAndRefreshUi(receiveState);
|
||||||
|
item.setOrder(0);
|
||||||
|
|
||||||
|
setSourceId(receiveState.getSourceId());
|
||||||
|
mSelectedPreference = item;
|
||||||
|
|
||||||
|
//refresh the header
|
||||||
|
if (mBluetoothFindBroadcastsHeaderController != null) {
|
||||||
|
mBluetoothFindBroadcastsHeaderController.refreshUi();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BluetoothBroadcastSourcePreference createBluetoothBroadcastSourcePreference() {
|
||||||
BluetoothBroadcastSourcePreference pref = new BluetoothBroadcastSourcePreference(
|
BluetoothBroadcastSourcePreference pref = new BluetoothBroadcastSourcePreference(
|
||||||
getContext(), source);
|
getContext());
|
||||||
pref.setKey(Integer.toString(source.getBroadcastId()));
|
|
||||||
pref.setOnPreferenceClickListener(preference -> {
|
pref.setOnPreferenceClickListener(preference -> {
|
||||||
if (source.isEncrypted()) {
|
if (pref.getBluetoothLeBroadcastMetadata() == null) {
|
||||||
|
Log.d(TAG, "BluetoothLeBroadcastMetadata is null, do nothing.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (pref.isEncrypted()) {
|
||||||
launchBroadcastCodeDialog(pref);
|
launchBroadcastCodeDialog(pref);
|
||||||
} else {
|
} else {
|
||||||
addSource(pref);
|
addSource(pref);
|
||||||
@@ -383,6 +410,10 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment
|
|||||||
.setPositiveButton(R.string.bluetooth_connect_access_dialog_positive,
|
.setPositiveButton(R.string.bluetooth_connect_access_dialog_positive,
|
||||||
(d, w) -> {
|
(d, w) -> {
|
||||||
Log.d(TAG, "setPositiveButton: clicked");
|
Log.d(TAG, "setPositiveButton: clicked");
|
||||||
|
if (pref.getBluetoothLeBroadcastMetadata() == null) {
|
||||||
|
Log.d(TAG, "BluetoothLeBroadcastMetadata is null, do nothing.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
addBroadcastCodeIntoPreference(pref, editText.getText().toString());
|
addBroadcastCodeIntoPreference(pref, editText.getText().toString());
|
||||||
addSource(pref);
|
addSource(pref);
|
||||||
})
|
})
|
||||||
@@ -392,6 +423,30 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment
|
|||||||
alertDialog.show();
|
alertDialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleSearchStarted() {
|
||||||
|
cacheRemoveAllPrefs(mBroadcastSourceListCategory);
|
||||||
|
addConnectedSourcePreference();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSourceRemoved() {
|
||||||
|
if (mSelectedPreference != null) {
|
||||||
|
if (mSelectedPreference.getBluetoothLeBroadcastMetadata() == null) {
|
||||||
|
mBroadcastSourceListCategory.removePreference(mSelectedPreference);
|
||||||
|
} else {
|
||||||
|
mSelectedPreference.clearReceiveState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mSelectedPreference = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addConnectedSourcePreference() {
|
||||||
|
List<BluetoothLeBroadcastReceiveState> receiveStateList =
|
||||||
|
mLeBroadcastAssistant.getAllSources(mCachedDevice.getDevice());
|
||||||
|
if (!receiveStateList.isEmpty()) {
|
||||||
|
updateListCategoryFromBroadcastReceiveState(receiveStateList.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int getSourceId() {
|
public int getSourceId() {
|
||||||
return mSourceId;
|
return mSourceId;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import com.android.settingslib.bluetooth.CachedBluetoothDevice;
|
|||||||
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
import com.android.settingslib.core.lifecycle.Lifecycle;
|
import com.android.settingslib.core.lifecycle.Lifecycle;
|
||||||
import com.android.settingslib.qrcode.QrCodeScanModeActivity;
|
|
||||||
import com.android.settingslib.widget.LayoutPreference;
|
import com.android.settingslib.widget.LayoutPreference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -135,7 +134,7 @@ public class BluetoothFindBroadcastsHeaderController extends BluetoothDetailsCon
|
|||||||
private void launchQrCodeScanner() {
|
private void launchQrCodeScanner() {
|
||||||
final Intent intent = new Intent(mContext, QrCodeScanModeActivity.class);
|
final Intent intent = new Intent(mContext, QrCodeScanModeActivity.class);
|
||||||
intent.setAction(BluetoothBroadcastUtils.ACTION_BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER)
|
intent.setAction(BluetoothBroadcastUtils.ACTION_BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER)
|
||||||
.putExtra(BluetoothBroadcastUtils.EXTRA_BLUETOOTH_SINK_IS_GROUP, false)
|
.putExtra(BluetoothBroadcastUtils.EXTRA_BLUETOOTH_SINK_IS_GROUP, true)
|
||||||
.putExtra(BluetoothBroadcastUtils.EXTRA_BLUETOOTH_DEVICE_SINK,
|
.putExtra(BluetoothBroadcastUtils.EXTRA_BLUETOOTH_DEVICE_SINK,
|
||||||
mCachedDevice.getDevice());
|
mCachedDevice.getDevice());
|
||||||
mContext.startActivity(intent);
|
mContext.startActivity(intent);
|
||||||
|
|||||||
111
src/com/android/settings/bluetooth/QrCodeScanModeActivity.java
Normal file
111
src/com/android/settings/bluetooth/QrCodeScanModeActivity.java
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* 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 static com.android.settingslib.bluetooth.BluetoothBroadcastUtils.EXTRA_BLUETOOTH_DEVICE_SINK;
|
||||||
|
import static com.android.settingslib.bluetooth.BluetoothBroadcastUtils.EXTRA_BLUETOOTH_SINK_IS_GROUP;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.fragment.app.FragmentTransaction;
|
||||||
|
|
||||||
|
import com.android.settingslib.R;
|
||||||
|
import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
|
||||||
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
|
|
||||||
|
//TODO (b/232365943): Add test case for tthe QrCode UI.
|
||||||
|
public class QrCodeScanModeActivity extends QrCodeScanModeBaseActivity {
|
||||||
|
private static final boolean DEBUG = BluetoothUtils.D;
|
||||||
|
private static final String TAG = "QrCodeScanModeActivity";
|
||||||
|
|
||||||
|
private boolean mIsGroupOp;
|
||||||
|
private BluetoothDevice mSink;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleIntent(Intent intent) {
|
||||||
|
String action = intent != null ? intent.getAction() : null;
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "handleIntent(), action = " + action);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action == null) {
|
||||||
|
finish();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case BluetoothBroadcastUtils.ACTION_BLUETOOTH_LE_AUDIO_QR_CODE_SCANNER:
|
||||||
|
showQrCodeScannerFragment(intent);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.e(TAG, "Launch with an invalid action");
|
||||||
|
}
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void showQrCodeScannerFragment(Intent intent) {
|
||||||
|
if (intent == null) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "intent is null, can not get bluetooth information from intent.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "showQrCodeScannerFragment");
|
||||||
|
}
|
||||||
|
|
||||||
|
mSink = intent.getParcelableExtra(EXTRA_BLUETOOTH_DEVICE_SINK);
|
||||||
|
mIsGroupOp = intent.getBooleanExtra(EXTRA_BLUETOOTH_SINK_IS_GROUP, false);
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "get extra from intent");
|
||||||
|
}
|
||||||
|
|
||||||
|
QrCodeScanModeFragment fragment =
|
||||||
|
(QrCodeScanModeFragment) mFragmentManager.findFragmentByTag(
|
||||||
|
BluetoothBroadcastUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
|
||||||
|
|
||||||
|
if (fragment == null) {
|
||||||
|
fragment = new QrCodeScanModeFragment(mIsGroupOp, mSink);
|
||||||
|
} else {
|
||||||
|
if (fragment.isVisible()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When the fragment in back stack but not on top of the stack, we can simply pop
|
||||||
|
// stack because current fragment transactions are arranged in an order
|
||||||
|
mFragmentManager.popBackStackImmediate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
|
||||||
|
|
||||||
|
fragmentTransaction.replace(R.id.fragment_container, fragment,
|
||||||
|
BluetoothBroadcastUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
|
||||||
|
fragmentTransaction.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* 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.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
|
import com.android.settingslib.R;
|
||||||
|
import com.android.settingslib.core.lifecycle.ObservableActivity;
|
||||||
|
|
||||||
|
public abstract class QrCodeScanModeBaseActivity extends ObservableActivity {
|
||||||
|
|
||||||
|
protected FragmentManager mFragmentManager;
|
||||||
|
|
||||||
|
protected abstract void handleIntent(Intent intent);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setTheme(R.style.SudThemeGlifV3_DayNight);
|
||||||
|
|
||||||
|
setContentView(R.layout.qrcode_scan_mode_activity);
|
||||||
|
mFragmentManager = getSupportFragmentManager();
|
||||||
|
|
||||||
|
if (savedInstanceState == null) {
|
||||||
|
handleIntent(getIntent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothLeBroadcastMetadata;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
|
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastMetadata;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothManager;
|
||||||
|
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
|
||||||
|
|
||||||
|
public class QrCodeScanModeController {
|
||||||
|
|
||||||
|
private static final boolean DEBUG = BluetoothUtils.D;
|
||||||
|
private static final String TAG = "QrCodeScanModeController";
|
||||||
|
|
||||||
|
private LocalBluetoothLeBroadcastMetadata mLocalBroadcastMetadata;
|
||||||
|
private LocalBluetoothLeBroadcastAssistant mLocalBroadcastAssistant;
|
||||||
|
private LocalBluetoothManager mLocalBluetoothManager;
|
||||||
|
private LocalBluetoothProfileManager mProfileManager;
|
||||||
|
|
||||||
|
public QrCodeScanModeController(Context context) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "QrCodeScanModeController constructor.");
|
||||||
|
}
|
||||||
|
mLocalBluetoothManager = Utils.getLocalBtManager(context);
|
||||||
|
mProfileManager = mLocalBluetoothManager.getProfileManager();
|
||||||
|
mLocalBroadcastMetadata = new LocalBluetoothLeBroadcastMetadata();
|
||||||
|
CachedBluetoothDeviceManager cachedDeviceManager = new CachedBluetoothDeviceManager(context,
|
||||||
|
mLocalBluetoothManager);
|
||||||
|
mLocalBroadcastAssistant = new LocalBluetoothLeBroadcastAssistant(context,
|
||||||
|
cachedDeviceManager, mProfileManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BluetoothLeBroadcastMetadata convertToBroadcastMetadata(String qrCodeString) {
|
||||||
|
return mLocalBroadcastMetadata.convertToBroadcastMetadata(qrCodeString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSource(BluetoothDevice sink, String sourceMetadata,
|
||||||
|
boolean isGroupOp) {
|
||||||
|
mLocalBroadcastAssistant.addSource(sink,
|
||||||
|
convertToBroadcastMetadata(sourceMetadata), isGroupOp);
|
||||||
|
}
|
||||||
|
}
|
||||||
243
src/com/android/settings/bluetooth/QrCodeScanModeFragment.java
Normal file
243
src/com/android/settings/bluetooth/QrCodeScanModeFragment.java
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
/**
|
||||||
|
* 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.app.settings.SettingsEnums;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.Outline;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.SurfaceTexture;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Size;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.TextureView;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewOutlineProvider;
|
||||||
|
import android.view.accessibility.AccessibilityEvent;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.android.settings.core.InstrumentedFragment;
|
||||||
|
import com.android.settingslib.R;
|
||||||
|
import com.android.settingslib.bluetooth.BluetoothBroadcastUtils;
|
||||||
|
import com.android.settingslib.bluetooth.BluetoothUtils;
|
||||||
|
import com.android.settingslib.core.lifecycle.ObservableFragment;
|
||||||
|
import com.android.settingslib.qrcode.QrCamera;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.StringRes;
|
||||||
|
|
||||||
|
public class QrCodeScanModeFragment extends InstrumentedFragment implements
|
||||||
|
TextureView.SurfaceTextureListener,
|
||||||
|
QrCamera.ScannerCallback {
|
||||||
|
private static final boolean DEBUG = BluetoothUtils.D;
|
||||||
|
private static final String TAG = "QrCodeScanModeFragment";
|
||||||
|
|
||||||
|
/** Message sent to hide error message */
|
||||||
|
private static final int MESSAGE_HIDE_ERROR_MESSAGE = 1;
|
||||||
|
/** Message sent to show error message */
|
||||||
|
private static final int MESSAGE_SHOW_ERROR_MESSAGE = 2;
|
||||||
|
/** Message sent to broadcast QR code */
|
||||||
|
private static final int MESSAGE_SCAN_BROADCAST_SUCCESS = 3;
|
||||||
|
|
||||||
|
private static final long SHOW_ERROR_MESSAGE_INTERVAL = 10000;
|
||||||
|
private static final long SHOW_SUCCESS_SQUARE_INTERVAL = 1000;
|
||||||
|
|
||||||
|
private boolean mIsGroupOp;
|
||||||
|
private int mCornerRadius;
|
||||||
|
private BluetoothDevice mSink;
|
||||||
|
private String mBroadcastMetadata;
|
||||||
|
private Context mContext;
|
||||||
|
private QrCamera mCamera;
|
||||||
|
private QrCodeScanModeController mController;
|
||||||
|
private TextureView mTextureView;
|
||||||
|
private TextView mSummary;
|
||||||
|
private TextView mErrorMessage;
|
||||||
|
|
||||||
|
public QrCodeScanModeFragment(boolean isGroupOp, BluetoothDevice sink) {
|
||||||
|
mIsGroupOp = isGroupOp;
|
||||||
|
mSink = sink;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
mContext = getContext();
|
||||||
|
mController = new QrCodeScanModeController(mContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
return inflater.inflate(R.layout.qrcode_scanner_fragment, container,
|
||||||
|
/* attachToRoot */ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||||
|
mTextureView = view.findViewById(R.id.preview_view);
|
||||||
|
mCornerRadius = mContext.getResources().getDimensionPixelSize(
|
||||||
|
R.dimen.qrcode_preview_radius);
|
||||||
|
mTextureView.setSurfaceTextureListener(this);
|
||||||
|
mTextureView.setOutlineProvider(new ViewOutlineProvider() {
|
||||||
|
@Override
|
||||||
|
public void getOutline(View view, Outline outline) {
|
||||||
|
outline.setRoundRect(0,0, view.getWidth(), view.getHeight(), mCornerRadius);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mTextureView.setClipToOutline(true);
|
||||||
|
mErrorMessage = view.findViewById(R.id.error_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initCamera(SurfaceTexture surface) {
|
||||||
|
// Check if the camera has already created.
|
||||||
|
if (mCamera == null) {
|
||||||
|
mCamera = new QrCamera(mContext, this);
|
||||||
|
mCamera.start(surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void destroyCamera() {
|
||||||
|
if (mCamera != null) {
|
||||||
|
mCamera.stop();
|
||||||
|
mCamera = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
|
||||||
|
initCamera(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width,
|
||||||
|
int height) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
|
||||||
|
destroyCamera();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleSuccessfulResult(String qrCode) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.d(TAG, "handleSuccessfulResult(), get the qr code string.");
|
||||||
|
}
|
||||||
|
mBroadcastMetadata = qrCode;
|
||||||
|
handleBtLeAudioScanner();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleCameraFailure() {
|
||||||
|
destroyCamera();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Size getViewSize() {
|
||||||
|
return new Size(mTextureView.getWidth(), mTextureView.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Rect getFramePosition(Size previewSize, int cameraOrientation) {
|
||||||
|
return new Rect(0, 0, previewSize.getHeight(), previewSize.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTransform(Matrix transform) {
|
||||||
|
mTextureView.setTransform(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid(String qrCode) {
|
||||||
|
if (qrCode.startsWith(BluetoothBroadcastUtils.SCHEME_BT_BROADCAST_METADATA)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
showErrorMessage(R.string.bt_le_audio_qr_code_is_not_valid_format);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isDecodeTaskAlive() {
|
||||||
|
return mCamera != null && mCamera.isDecodeTaskAlive();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Handler mHandler = new Handler() {
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msg) {
|
||||||
|
switch (msg.what) {
|
||||||
|
case MESSAGE_HIDE_ERROR_MESSAGE:
|
||||||
|
mErrorMessage.setVisibility(View.INVISIBLE);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MESSAGE_SHOW_ERROR_MESSAGE:
|
||||||
|
final String errorMessage = (String) msg.obj;
|
||||||
|
|
||||||
|
mErrorMessage.setVisibility(View.VISIBLE);
|
||||||
|
mErrorMessage.setText(errorMessage);
|
||||||
|
mErrorMessage.sendAccessibilityEvent(
|
||||||
|
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
|
||||||
|
|
||||||
|
// Cancel any pending messages to hide error view and requeue the message so
|
||||||
|
// user has time to see error
|
||||||
|
removeMessages(MESSAGE_HIDE_ERROR_MESSAGE);
|
||||||
|
sendEmptyMessageDelayed(MESSAGE_HIDE_ERROR_MESSAGE,
|
||||||
|
SHOW_ERROR_MESSAGE_INTERVAL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MESSAGE_SCAN_BROADCAST_SUCCESS:
|
||||||
|
mController.addSource(mSink, mBroadcastMetadata, mIsGroupOp);
|
||||||
|
updateSummary();
|
||||||
|
mSummary.sendAccessibilityEvent(
|
||||||
|
AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private void showErrorMessage(@StringRes int messageResId) {
|
||||||
|
final Message message = mHandler.obtainMessage(MESSAGE_SHOW_ERROR_MESSAGE,
|
||||||
|
getString(messageResId));
|
||||||
|
message.sendToTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleBtLeAudioScanner() {
|
||||||
|
Message message = mHandler.obtainMessage(MESSAGE_SCAN_BROADCAST_SUCCESS);
|
||||||
|
mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSummary() {
|
||||||
|
mSummary.setText(getString(R.string.bt_le_audio_scan_qr_code_scanner,
|
||||||
|
null /* broadcast_name*/));;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMetricsCategory() {
|
||||||
|
return SettingsEnums.LE_AUDIO_BROADCAST_SCAN_QR_CODE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -84,10 +84,19 @@ public class ProfileSelectStorageFragment extends ProfileSelectFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final StorageEntry changedStorageEntry = new StorageEntry(getContext(), volumeInfo);
|
final StorageEntry changedStorageEntry = new StorageEntry(getContext(), volumeInfo);
|
||||||
switch (volumeInfo.getState()) {
|
final int volumeState = volumeInfo.getState();
|
||||||
|
switch (volumeState) {
|
||||||
|
case VolumeInfo.STATE_REMOVED:
|
||||||
|
case VolumeInfo.STATE_BAD_REMOVAL:
|
||||||
|
// Remove removed storage from list and don't show it on spinner.
|
||||||
|
if (!mStorageEntries.remove(changedStorageEntry)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
case VolumeInfo.STATE_MOUNTED:
|
case VolumeInfo.STATE_MOUNTED:
|
||||||
case VolumeInfo.STATE_MOUNTED_READ_ONLY:
|
case VolumeInfo.STATE_MOUNTED_READ_ONLY:
|
||||||
case VolumeInfo.STATE_UNMOUNTABLE:
|
case VolumeInfo.STATE_UNMOUNTABLE:
|
||||||
|
case VolumeInfo.STATE_UNMOUNTED:
|
||||||
|
case VolumeInfo.STATE_EJECTING:
|
||||||
// Add mounted or unmountable storage in the list and show it on spinner.
|
// Add mounted or unmountable storage in the list and show it on spinner.
|
||||||
// Unmountable storages are the storages which has a problem format and android
|
// Unmountable storages are the storages which has a problem format and android
|
||||||
// is not able to mount it automatically.
|
// is not able to mount it automatically.
|
||||||
@@ -95,25 +104,15 @@ public class ProfileSelectStorageFragment extends ProfileSelectFragment {
|
|||||||
mStorageEntries.removeIf(storageEntry -> {
|
mStorageEntries.removeIf(storageEntry -> {
|
||||||
return storageEntry.equals(changedStorageEntry);
|
return storageEntry.equals(changedStorageEntry);
|
||||||
});
|
});
|
||||||
|
if (volumeState != VolumeInfo.STATE_REMOVED
|
||||||
|
&& volumeState != VolumeInfo.STATE_BAD_REMOVAL) {
|
||||||
mStorageEntries.add(changedStorageEntry);
|
mStorageEntries.add(changedStorageEntry);
|
||||||
|
}
|
||||||
if (changedStorageEntry.equals(mSelectedStorageEntry)) {
|
if (changedStorageEntry.equals(mSelectedStorageEntry)) {
|
||||||
mSelectedStorageEntry = changedStorageEntry;
|
mSelectedStorageEntry = changedStorageEntry;
|
||||||
}
|
}
|
||||||
refreshUi();
|
refreshUi();
|
||||||
break;
|
break;
|
||||||
case VolumeInfo.STATE_REMOVED:
|
|
||||||
case VolumeInfo.STATE_UNMOUNTED:
|
|
||||||
case VolumeInfo.STATE_BAD_REMOVAL:
|
|
||||||
case VolumeInfo.STATE_EJECTING:
|
|
||||||
// Remove removed storage from list and don't show it on spinner.
|
|
||||||
if (mStorageEntries.remove(changedStorageEntry)) {
|
|
||||||
if (changedStorageEntry.equals(mSelectedStorageEntry)) {
|
|
||||||
mSelectedStorageEntry =
|
|
||||||
StorageEntry.getDefaultInternalStorageEntry(getContext());
|
|
||||||
}
|
|
||||||
refreshUi();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import com.android.settingslib.net.NetworkCycleData;
|
|||||||
import com.android.settingslib.widget.SettingsSpinnerAdapter;
|
import com.android.settingslib.widget.SettingsSpinnerAdapter;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem> {
|
public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem> {
|
||||||
|
|
||||||
@@ -67,7 +66,7 @@ public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem>
|
|||||||
* Rebuild list based on network data. Always selects the newest item,
|
* Rebuild list based on network data. Always selects the newest item,
|
||||||
* updating the inspection range on chartData.
|
* updating the inspection range on chartData.
|
||||||
*/
|
*/
|
||||||
public boolean updateCycleList(List<? extends NetworkCycleData> cycleData) {
|
public void updateCycleList(List<? extends NetworkCycleData> cycleData) {
|
||||||
mSpinner.setOnItemSelectedListener(mListener);
|
mSpinner.setOnItemSelectedListener(mListener);
|
||||||
// stash away currently selected cycle to try restoring below
|
// stash away currently selected cycle to try restoring below
|
||||||
final CycleAdapter.CycleItem previousItem = (CycleAdapter.CycleItem)
|
final CycleAdapter.CycleItem previousItem = (CycleAdapter.CycleItem)
|
||||||
@@ -83,17 +82,8 @@ public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem>
|
|||||||
if (getCount() > 0) {
|
if (getCount() > 0) {
|
||||||
final int position = findNearestPosition(previousItem);
|
final int position = findNearestPosition(previousItem);
|
||||||
mSpinner.setSelection(position);
|
mSpinner.setSelection(position);
|
||||||
|
|
||||||
// only force-update cycle when changed; skipping preserves any
|
|
||||||
// user-defined inspection region.
|
|
||||||
final CycleAdapter.CycleItem selectedItem = getItem(position);
|
|
||||||
if (!Objects.equals(selectedItem, previousItem)) {
|
|
||||||
mListener.onItemSelected(null, null, position, 0);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List item that reflects a specific data usage cycle.
|
* List item that reflects a specific data usage cycle.
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ import com.android.settingslib.net.UidDetailProvider;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Panel showing data usage history across various networks, including options
|
* Panel showing data usage history across various networks, including options
|
||||||
@@ -111,7 +112,11 @@ public class DataUsageList extends DataUsageBaseFragment
|
|||||||
|
|
||||||
private ChartDataUsagePreference mChart;
|
private ChartDataUsagePreference mChart;
|
||||||
private List<NetworkCycleChartData> mCycleData;
|
private List<NetworkCycleChartData> mCycleData;
|
||||||
|
// Caches the cycles for startAppDataUsage usage, which need be cleared when resumed.
|
||||||
private ArrayList<Long> mCycles;
|
private ArrayList<Long> mCycles;
|
||||||
|
// Spinner will keep the selected cycle even after paused, this only keeps the displayed cycle,
|
||||||
|
// which need be cleared when resumed.
|
||||||
|
private CycleAdapter.CycleItem mLastDisplayedCycle;
|
||||||
private UidDetailProvider mUidDetailProvider;
|
private UidDetailProvider mUidDetailProvider;
|
||||||
private CycleAdapter mCycleAdapter;
|
private CycleAdapter mCycleAdapter;
|
||||||
private Preference mUsageAmount;
|
private Preference mUsageAmount;
|
||||||
@@ -199,13 +204,15 @@ public class DataUsageList extends DataUsageBaseFragment
|
|||||||
|
|
||||||
mLoadingViewController = new LoadingViewController(
|
mLoadingViewController = new LoadingViewController(
|
||||||
getView().findViewById(R.id.loading_container), getListView());
|
getView().findViewById(R.id.loading_container), getListView());
|
||||||
mLoadingViewController.showLoadingViewDelayed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
mLoadingViewController.showLoadingViewDelayed();
|
||||||
mDataStateListener.start(mSubId);
|
mDataStateListener.start(mSubId);
|
||||||
|
mCycles = null;
|
||||||
|
mLastDisplayedCycle = null;
|
||||||
|
|
||||||
// kick off loader for network history
|
// kick off loader for network history
|
||||||
// TODO: consider chaining two loaders together instead of reloading
|
// TODO: consider chaining two loaders together instead of reloading
|
||||||
@@ -319,9 +326,46 @@ public class DataUsageList extends DataUsageBaseFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generate cycle list based on policy and available history
|
// generate cycle list based on policy and available history
|
||||||
if (mCycleAdapter.updateCycleList(mCycleData)) {
|
mCycleAdapter.updateCycleList(mCycleData);
|
||||||
updateDetailData();
|
updateSelectedCycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the chart and detail data when initial loaded or selected cycle changed.
|
||||||
|
*/
|
||||||
|
private void updateSelectedCycle() {
|
||||||
|
// Avoid from updating UI after #onStop.
|
||||||
|
if (!getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid from updating UI when async query still on-going.
|
||||||
|
// This could happen when a request from #onMobileDataEnabledChange.
|
||||||
|
if (mCycleData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int position = mCycleSpinner.getSelectedItemPosition();
|
||||||
|
if (mCycleAdapter.getCount() == 0 || position < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final CycleAdapter.CycleItem cycle = mCycleAdapter.getItem(position);
|
||||||
|
if (Objects.equals(cycle, mLastDisplayedCycle)) {
|
||||||
|
// Avoid duplicate update to avoid page flash.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mLastDisplayedCycle = cycle;
|
||||||
|
|
||||||
|
if (LOGD) {
|
||||||
|
Log.d(TAG, "showing cycle " + cycle + ", [start=" + cycle.start + ", end="
|
||||||
|
+ cycle.end + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
// update chart to show selected cycle, and update detail data
|
||||||
|
// to match updated sweep bounds.
|
||||||
|
mChart.setNetworkCycleData(mCycleData.get(position));
|
||||||
|
|
||||||
|
updateDetailData();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -495,33 +539,10 @@ public class DataUsageList extends DataUsageBaseFragment
|
|||||||
return Math.max(largest, item.total);
|
return Math.max(largest, item.total);
|
||||||
}
|
}
|
||||||
|
|
||||||
private OnItemSelectedListener mCycleListener = new OnItemSelectedListener() {
|
private final OnItemSelectedListener mCycleListener = new OnItemSelectedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||||
final CycleAdapter.CycleItem cycle = (CycleAdapter.CycleItem)
|
updateSelectedCycle();
|
||||||
mCycleSpinner.getSelectedItem();
|
|
||||||
|
|
||||||
if (LOGD) {
|
|
||||||
Log.d(TAG, "showing cycle " + cycle + ", start=" + cycle.start + ", end="
|
|
||||||
+ cycle.end + "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid from updating UI after #onStop.
|
|
||||||
if (!getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Avoid from updating UI when async query still on-going.
|
|
||||||
// This could happen when a request from #onMobileDataEnabledChange.
|
|
||||||
if (mCycleData == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update chart to show selected cycle, and update detail data
|
|
||||||
// to match updated sweep bounds.
|
|
||||||
mChart.setNetworkCycleData(mCycleData.get(position));
|
|
||||||
|
|
||||||
updateDetailData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
package com.android.settings.datausage;
|
package com.android.settings.datausage;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -28,6 +29,7 @@ import com.android.settings.R;
|
|||||||
public class SpinnerPreference extends Preference implements CycleAdapter.SpinnerInterface {
|
public class SpinnerPreference extends Preference implements CycleAdapter.SpinnerInterface {
|
||||||
|
|
||||||
private CycleAdapter mAdapter;
|
private CycleAdapter mAdapter;
|
||||||
|
@Nullable
|
||||||
private AdapterView.OnItemSelectedListener mListener;
|
private AdapterView.OnItemSelectedListener mListener;
|
||||||
private Object mCurrentObject;
|
private Object mCurrentObject;
|
||||||
private int mPosition;
|
private int mPosition;
|
||||||
@@ -88,19 +90,24 @@ public class SpinnerPreference extends Preference implements CycleAdapter.Spinne
|
|||||||
view.findViewById(R.id.cycles_spinner).performClick();
|
view.findViewById(R.id.cycles_spinner).performClick();
|
||||||
}
|
}
|
||||||
|
|
||||||
private final AdapterView.OnItemSelectedListener mOnSelectedListener
|
private final AdapterView.OnItemSelectedListener mOnSelectedListener =
|
||||||
= new AdapterView.OnItemSelectedListener() {
|
new AdapterView.OnItemSelectedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemSelected(
|
||||||
|
AdapterView<?> parent, View view, int position, long id) {
|
||||||
if (mPosition == position) return;
|
if (mPosition == position) return;
|
||||||
mPosition = position;
|
mPosition = position;
|
||||||
mCurrentObject = mAdapter.getItem(position);
|
mCurrentObject = mAdapter.getItem(position);
|
||||||
|
if (mListener != null) {
|
||||||
mListener.onItemSelected(parent, view, position, id);
|
mListener.onItemSelected(parent, view, position, id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNothingSelected(AdapterView<?> parent) {
|
public void onNothingSelected(AdapterView<?> parent) {
|
||||||
|
if (mListener != null) {
|
||||||
mListener.onNothingSelected(parent);
|
mListener.onNothingSelected(parent);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,10 +115,19 @@ public class StorageDashboardFragment extends DashboardFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
final StorageEntry changedStorageEntry = new StorageEntry(getContext(), volumeInfo);
|
final StorageEntry changedStorageEntry = new StorageEntry(getContext(), volumeInfo);
|
||||||
switch (volumeInfo.getState()) {
|
final int volumeState = volumeInfo.getState();
|
||||||
|
switch (volumeState) {
|
||||||
|
case VolumeInfo.STATE_REMOVED:
|
||||||
|
case VolumeInfo.STATE_BAD_REMOVAL:
|
||||||
|
// Remove removed storage from list and don't show it on spinner.
|
||||||
|
if (!mStorageEntries.remove(changedStorageEntry)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
case VolumeInfo.STATE_MOUNTED:
|
case VolumeInfo.STATE_MOUNTED:
|
||||||
case VolumeInfo.STATE_MOUNTED_READ_ONLY:
|
case VolumeInfo.STATE_MOUNTED_READ_ONLY:
|
||||||
case VolumeInfo.STATE_UNMOUNTABLE:
|
case VolumeInfo.STATE_UNMOUNTABLE:
|
||||||
|
case VolumeInfo.STATE_UNMOUNTED:
|
||||||
|
case VolumeInfo.STATE_EJECTING:
|
||||||
// Add mounted or unmountable storage in the list and show it on spinner.
|
// Add mounted or unmountable storage in the list and show it on spinner.
|
||||||
// Unmountable storages are the storages which has a problem format and android
|
// Unmountable storages are the storages which has a problem format and android
|
||||||
// is not able to mount it automatically.
|
// is not able to mount it automatically.
|
||||||
@@ -126,25 +135,15 @@ public class StorageDashboardFragment extends DashboardFragment
|
|||||||
mStorageEntries.removeIf(storageEntry -> {
|
mStorageEntries.removeIf(storageEntry -> {
|
||||||
return storageEntry.equals(changedStorageEntry);
|
return storageEntry.equals(changedStorageEntry);
|
||||||
});
|
});
|
||||||
|
if (volumeState != VolumeInfo.STATE_REMOVED
|
||||||
|
&& volumeState != VolumeInfo.STATE_BAD_REMOVAL) {
|
||||||
mStorageEntries.add(changedStorageEntry);
|
mStorageEntries.add(changedStorageEntry);
|
||||||
|
}
|
||||||
if (changedStorageEntry.equals(mSelectedStorageEntry)) {
|
if (changedStorageEntry.equals(mSelectedStorageEntry)) {
|
||||||
mSelectedStorageEntry = changedStorageEntry;
|
mSelectedStorageEntry = changedStorageEntry;
|
||||||
}
|
}
|
||||||
refreshUi();
|
refreshUi();
|
||||||
break;
|
break;
|
||||||
case VolumeInfo.STATE_REMOVED:
|
|
||||||
case VolumeInfo.STATE_UNMOUNTED:
|
|
||||||
case VolumeInfo.STATE_BAD_REMOVAL:
|
|
||||||
case VolumeInfo.STATE_EJECTING:
|
|
||||||
// Remove removed storage from list and don't show it on spinner.
|
|
||||||
if (mStorageEntries.remove(changedStorageEntry)) {
|
|
||||||
if (changedStorageEntry.equals(mSelectedStorageEntry)) {
|
|
||||||
mSelectedStorageEntry =
|
|
||||||
StorageEntry.getDefaultInternalStorageEntry(getContext());
|
|
||||||
}
|
|
||||||
refreshUi();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import android.os.UserManager;
|
|||||||
import android.os.storage.DiskInfo;
|
import android.os.storage.DiskInfo;
|
||||||
import android.os.storage.StorageManager;
|
import android.os.storage.StorageManager;
|
||||||
import android.os.storage.VolumeInfo;
|
import android.os.storage.VolumeInfo;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
@@ -53,6 +54,8 @@ import java.util.Objects;
|
|||||||
public class VolumeOptionMenuController implements LifecycleObserver, OnCreateOptionsMenu,
|
public class VolumeOptionMenuController implements LifecycleObserver, OnCreateOptionsMenu,
|
||||||
OnPrepareOptionsMenu, OnOptionsItemSelected {
|
OnPrepareOptionsMenu, OnOptionsItemSelected {
|
||||||
|
|
||||||
|
private static final String TAG = "VolumeOptionMenuController";
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
MenuItem mRename;
|
MenuItem mRename;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -103,6 +106,17 @@ public class VolumeOptionMenuController implements LifecycleObserver, OnCreateOp
|
|||||||
mFree = menu.findItem(R.id.storage_free);
|
mFree = menu.findItem(R.id.storage_free);
|
||||||
mForget = menu.findItem(R.id.storage_forget);
|
mForget = menu.findItem(R.id.storage_forget);
|
||||||
|
|
||||||
|
updateOptionsMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateOptionsMenu() {
|
||||||
|
if (mRename == null || mMount == null || mUnmount == null || mFormat == null
|
||||||
|
|| mFormatAsPortable == null || mFormatAsInternal == null || mMigrate == null
|
||||||
|
|| mFree == null || mForget == null) {
|
||||||
|
Log.d(TAG, "Menu items are not available");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mRename.setVisible(false);
|
mRename.setVisible(false);
|
||||||
mMount.setVisible(false);
|
mMount.setVisible(false);
|
||||||
mUnmount.setVisible(false);
|
mUnmount.setVisible(false);
|
||||||
@@ -252,5 +266,7 @@ public class VolumeOptionMenuController implements LifecycleObserver, OnCreateOp
|
|||||||
|
|
||||||
public void setSelectedStorageEntry(StorageEntry storageEntry) {
|
public void setSelectedStorageEntry(StorageEntry storageEntry) {
|
||||||
mStorageEntry = storageEntry;
|
mStorageEntry = storageEntry;
|
||||||
|
|
||||||
|
updateOptionsMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import static android.provider.Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY
|
|||||||
import static android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY;
|
import static android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_HIGHLIGHT_MENU_KEY;
|
||||||
import static android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI;
|
import static android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI;
|
||||||
|
|
||||||
|
import static com.android.settings.SettingsActivity.EXTRA_USER_HANDLE;
|
||||||
|
|
||||||
import android.animation.LayoutTransition;
|
import android.animation.LayoutTransition;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
@@ -27,6 +29,7 @@ import android.content.ComponentName;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.UserHandle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.FeatureFlagUtils;
|
import android.util.FeatureFlagUtils;
|
||||||
@@ -449,8 +452,14 @@ public class SettingsHomepageActivity extends FragmentActivity implements
|
|||||||
SplitRule.FINISH_ALWAYS,
|
SplitRule.FINISH_ALWAYS,
|
||||||
SplitRule.FINISH_ALWAYS,
|
SplitRule.FINISH_ALWAYS,
|
||||||
true /* clearTop */);
|
true /* clearTop */);
|
||||||
|
|
||||||
|
final UserHandle user = intent.getParcelableExtra(EXTRA_USER_HANDLE, UserHandle.class);
|
||||||
|
if (user != null) {
|
||||||
|
startActivityAsUser(targetIntent, user);
|
||||||
|
} else {
|
||||||
startActivity(targetIntent);
|
startActivity(targetIntent);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String getHighlightMenuKey() {
|
private String getHighlightMenuKey() {
|
||||||
final Intent intent = getIntent();
|
final Intent intent = getIntent();
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ public class AppLocalePickerActivity extends SettingsBaseActivity
|
|||||||
|
|
||||||
/** Sets the app's locale to the supplied language tag */
|
/** Sets the app's locale to the supplied language tag */
|
||||||
private void setAppDefaultLocale(String languageTag) {
|
private void setAppDefaultLocale(String languageTag) {
|
||||||
|
Log.d(TAG, "setAppDefaultLocale: " + languageTag);
|
||||||
LocaleManager localeManager = mContextAsUser.getSystemService(LocaleManager.class);
|
LocaleManager localeManager = mContextAsUser.getSystemService(LocaleManager.class);
|
||||||
if (localeManager == null) {
|
if (localeManager == null) {
|
||||||
Log.w(TAG, "LocaleManager is null, cannot set default app locale");
|
Log.w(TAG, "LocaleManager is null, cannot set default app locale");
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ import com.android.settings.datausage.DataUsagePreference;
|
|||||||
import com.android.settings.datausage.DataUsageUtils;
|
import com.android.settings.datausage.DataUsageUtils;
|
||||||
import com.android.settings.location.WifiScanningFragment;
|
import com.android.settings.location.WifiScanningFragment;
|
||||||
import com.android.settings.search.BaseSearchIndexProvider;
|
import com.android.settings.search.BaseSearchIndexProvider;
|
||||||
import com.android.settings.utils.AnnotationSpan;
|
|
||||||
import com.android.settings.wifi.AddNetworkFragment;
|
import com.android.settings.wifi.AddNetworkFragment;
|
||||||
import com.android.settings.wifi.AddWifiNetworkPreference;
|
import com.android.settings.wifi.AddWifiNetworkPreference;
|
||||||
import com.android.settings.wifi.ConfigureWifiEntryFragment;
|
import com.android.settings.wifi.ConfigureWifiEntryFragment;
|
||||||
@@ -829,12 +828,10 @@ public class NetworkProviderSettings extends RestrictedSettingsFragment
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (TextUtils.isEmpty(mWifiStatusMessagePreference.getTitle())) {
|
if (TextUtils.isEmpty(mWifiStatusMessagePreference.getTitle())) {
|
||||||
AnnotationSpan.LinkInfo info = new AnnotationSpan.LinkInfo(
|
mWifiStatusMessagePreference.setTitle(R.string.wifi_scan_notify_message);
|
||||||
AnnotationSpan.LinkInfo.DEFAULT_ANNOTATION,
|
mWifiStatusMessagePreference.setLearnMoreText(
|
||||||
v -> launchWifiScanningFragment());
|
context.getString(R.string.wifi_scan_change));
|
||||||
CharSequence text = AnnotationSpan.linkify(
|
mWifiStatusMessagePreference.setLearnMoreAction(v -> launchWifiScanningFragment());
|
||||||
context.getText(R.string.wifi_scan_notify_message), info);
|
|
||||||
mWifiStatusMessagePreference.setTitle(text);
|
|
||||||
}
|
}
|
||||||
mWifiStatusMessagePreference.setVisible(true);
|
mWifiStatusMessagePreference.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROF
|
|||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.provider.SearchIndexableResource;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
@@ -36,6 +37,7 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
|
|||||||
import com.android.settingslib.search.SearchIndexable;
|
import com.android.settingslib.search.SearchIndexable;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@SearchIndexable
|
@SearchIndexable
|
||||||
@@ -72,12 +74,6 @@ public class PrivacyDashboardFragment extends DashboardFragment {
|
|||||||
replaceEnterpriseStringSummary("work_policy_info",
|
replaceEnterpriseStringSummary("work_policy_info",
|
||||||
WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY,
|
WORK_PROFILE_PRIVACY_POLICY_INFO_SUMMARY,
|
||||||
R.string.work_policy_privacy_settings_summary);
|
R.string.work_policy_privacy_settings_summary);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected int getPreferenceScreenResId() {
|
|
||||||
return R.xml.privacy_dashboard_settings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -90,6 +86,19 @@ public class PrivacyDashboardFragment extends DashboardFragment {
|
|||||||
return buildPreferenceControllers(context, getSettingsLifecycle());
|
return buildPreferenceControllers(context, getSettingsLifecycle());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getPreferenceScreenResId() {
|
||||||
|
return getPreferenceScreenResId(getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getPreferenceScreenResId(Context context) {
|
||||||
|
if (SafetyCenterManagerWrapper.get().isEnabled(context)) {
|
||||||
|
return R.xml.privacy_advanced_settings;
|
||||||
|
} else {
|
||||||
|
return R.xml.privacy_dashboard_settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static List<AbstractPreferenceController> buildPreferenceControllers(
|
private static List<AbstractPreferenceController> buildPreferenceControllers(
|
||||||
Context context, Lifecycle lifecycle) {
|
Context context, Lifecycle lifecycle) {
|
||||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||||
@@ -108,17 +117,19 @@ public class PrivacyDashboardFragment extends DashboardFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
|
||||||
new BaseSearchIndexProvider(R.xml.privacy_dashboard_settings) {
|
new BaseSearchIndexProvider() {
|
||||||
|
@Override
|
||||||
|
public List<SearchIndexableResource> getXmlResourcesToIndex(
|
||||||
|
Context context, boolean enabled) {
|
||||||
|
final SearchIndexableResource sir = new SearchIndexableResource(context);
|
||||||
|
sir.xmlResId = getPreferenceScreenResId(context);
|
||||||
|
return Arrays.asList(sir);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<AbstractPreferenceController> createPreferenceControllers(
|
public List<AbstractPreferenceController> createPreferenceControllers(
|
||||||
Context context) {
|
Context context) {
|
||||||
return buildPreferenceControllers(context, null);
|
return buildPreferenceControllers(context, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isPageSearchEnabled(Context context) {
|
|
||||||
return !SafetyCenterManagerWrapper.get().isEnabled(context);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ public class SafetySourceBroadcastReceiver extends BroadcastReceiver {
|
|||||||
if (ACTION_REFRESH_SAFETY_SOURCES.equals(intent.getAction())) {
|
if (ACTION_REFRESH_SAFETY_SOURCES.equals(intent.getAction())) {
|
||||||
String[] sourceIdsExtra =
|
String[] sourceIdsExtra =
|
||||||
intent.getStringArrayExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS);
|
intent.getStringArrayExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS);
|
||||||
if (sourceIdsExtra != null && sourceIdsExtra.length > 0) {
|
|
||||||
final String refreshBroadcastId = intent.getStringExtra(
|
final String refreshBroadcastId = intent.getStringExtra(
|
||||||
SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID);
|
SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID);
|
||||||
|
if (sourceIdsExtra != null && sourceIdsExtra.length > 0 && refreshBroadcastId != null) {
|
||||||
final SafetyEvent safetyEvent = new SafetyEvent.Builder(
|
final SafetyEvent safetyEvent = new SafetyEvent.Builder(
|
||||||
SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
|
SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
|
||||||
.setRefreshBroadcastId(refreshBroadcastId).build();
|
.setRefreshBroadcastId(refreshBroadcastId).build();
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import android.content.Context;
|
|||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.widget.Switch;
|
import android.widget.Switch;
|
||||||
|
|
||||||
import androidx.core.content.res.TypedArrayUtils;
|
import androidx.core.content.res.TypedArrayUtils;
|
||||||
@@ -33,6 +34,8 @@ import com.android.settings.widget.SettingsMainSwitchBar.OnBeforeCheckedChangeLi
|
|||||||
import com.android.settingslib.RestrictedPreferenceHelper;
|
import com.android.settingslib.RestrictedPreferenceHelper;
|
||||||
import com.android.settingslib.widget.OnMainSwitchChangeListener;
|
import com.android.settingslib.widget.OnMainSwitchChangeListener;
|
||||||
|
|
||||||
|
import com.google.android.setupdesign.util.LayoutStyler;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -48,6 +51,7 @@ public class SettingsMainSwitchPreference extends TwoStatePreference implements
|
|||||||
new ArrayList<>();
|
new ArrayList<>();
|
||||||
private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
|
private final List<OnMainSwitchChangeListener> mSwitchChangeListeners = new ArrayList<>();
|
||||||
|
|
||||||
|
private boolean mApplyPartnerCustomizationPaddingStyle;
|
||||||
private SettingsMainSwitchBar mMainSwitchBar;
|
private SettingsMainSwitchBar mMainSwitchBar;
|
||||||
private CharSequence mTitle;
|
private CharSequence mTitle;
|
||||||
private EnforcedAdmin mEnforcedAdmin;
|
private EnforcedAdmin mEnforcedAdmin;
|
||||||
@@ -95,6 +99,12 @@ public class SettingsMainSwitchPreference extends TwoStatePreference implements
|
|||||||
} else {
|
} else {
|
||||||
mMainSwitchBar.hide();
|
mMainSwitchBar.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mApplyPartnerCustomizationPaddingStyle) {
|
||||||
|
// TODO(b/232494666): Replace all margins of the root view with the padding
|
||||||
|
final ViewGroup parentView = (ViewGroup) mMainSwitchBar.getParent();
|
||||||
|
LayoutStyler.applyPartnerCustomizationLayoutPaddingStyle(parentView);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init(Context context, AttributeSet attrs) {
|
private void init(Context context, AttributeSet attrs) {
|
||||||
@@ -241,6 +251,14 @@ public class SettingsMainSwitchPreference extends TwoStatePreference implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apples the padding style of the partner's customization. It's used in the SetupWizard.
|
||||||
|
*/
|
||||||
|
public void applyPartnerCustomizationPaddingStyle() {
|
||||||
|
mApplyPartnerCustomizationPaddingStyle = true;
|
||||||
|
notifyChanged();
|
||||||
|
}
|
||||||
|
|
||||||
private void initMainSwitchBar() {
|
private void initMainSwitchBar() {
|
||||||
if (mMainSwitchBar != null) {
|
if (mMainSwitchBar != null) {
|
||||||
mMainSwitchBar.setTitle(mTitle);
|
mMainSwitchBar.setTitle(mTitle);
|
||||||
|
|||||||
@@ -20,26 +20,30 @@ import android.app.Dialog;
|
|||||||
import android.app.settings.SettingsEnums;
|
import android.app.settings.SettingsEnums;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.ApplicationInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.fragment.app.DialogFragment;
|
import androidx.fragment.app.DialogFragment;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||||
|
import com.android.settingslib.wifi.WifiPermissionChecker;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This activity requests users permission to allow scanning even when Wi-Fi is turned off
|
* This activity requests users permission to allow scanning even when Wi-Fi is turned off
|
||||||
*/
|
*/
|
||||||
public class WifiScanModeActivity extends FragmentActivity {
|
public class WifiScanModeActivity extends FragmentActivity {
|
||||||
private DialogFragment mDialog;
|
private DialogFragment mDialog;
|
||||||
private String mApp;
|
@VisibleForTesting
|
||||||
|
String mApp;
|
||||||
|
@VisibleForTesting
|
||||||
|
WifiPermissionChecker mWifiPermissionChecker;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
@@ -50,13 +54,7 @@ public class WifiScanModeActivity extends FragmentActivity {
|
|||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
if (intent != null && WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
|
if (intent != null && WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE
|
||||||
.equals(intent.getAction())) {
|
.equals(intent.getAction())) {
|
||||||
ApplicationInfo ai;
|
refreshAppLabel();
|
||||||
mApp = getCallingPackage();
|
|
||||||
try {
|
|
||||||
PackageManager pm = getPackageManager();
|
|
||||||
ai = pm.getApplicationInfo(mApp, 0);
|
|
||||||
mApp = (String)pm.getApplicationLabel(ai);
|
|
||||||
} catch (PackageManager.NameNotFoundException e) { }
|
|
||||||
} else {
|
} else {
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
@@ -67,6 +65,19 @@ public class WifiScanModeActivity extends FragmentActivity {
|
|||||||
createDialog();
|
createDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void refreshAppLabel() {
|
||||||
|
if (mWifiPermissionChecker == null) {
|
||||||
|
mWifiPermissionChecker = new WifiPermissionChecker(this);
|
||||||
|
}
|
||||||
|
String packageName = mWifiPermissionChecker.getLaunchedPackage();
|
||||||
|
if (TextUtils.isEmpty(packageName)) {
|
||||||
|
mApp = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mApp = Utils.getApplicationLabel(getApplicationContext(), packageName).toString();
|
||||||
|
}
|
||||||
|
|
||||||
private void createDialog() {
|
private void createDialog() {
|
||||||
if (mDialog == null) {
|
if (mDialog == null) {
|
||||||
mDialog = AlertDialogFragment.newInstance(mApp);
|
mDialog = AlertDialogFragment.newInstance(mApp);
|
||||||
|
|||||||
@@ -30,13 +30,12 @@ import android.view.ViewGroup;
|
|||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.fragment.app.FragmentActivity;
|
|
||||||
import androidx.fragment.app.FragmentManager;
|
import androidx.fragment.app.FragmentManager;
|
||||||
import androidx.fragment.app.FragmentPagerAdapter;
|
import androidx.fragment.app.FragmentPagerAdapter;
|
||||||
|
|
||||||
import com.android.internal.util.CollectionUtils;
|
import com.android.internal.util.CollectionUtils;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.core.InstrumentedFragment;
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
import com.android.settings.network.ActiveSubscriptionsListener;
|
import com.android.settings.network.ActiveSubscriptionsListener;
|
||||||
import com.android.settings.network.SubscriptionUtil;
|
import com.android.settings.network.SubscriptionUtil;
|
||||||
import com.android.settings.network.ims.WifiCallingQueryImsState;
|
import com.android.settings.network.ims.WifiCallingQueryImsState;
|
||||||
@@ -54,7 +53,8 @@ import java.util.List;
|
|||||||
* "Wi-Fi Calling settings" screen. This is the container fragment which holds
|
* "Wi-Fi Calling settings" screen. This is the container fragment which holds
|
||||||
* {@link WifiCallingSettingsForSub} fragments.
|
* {@link WifiCallingSettingsForSub} fragments.
|
||||||
*/
|
*/
|
||||||
public class WifiCallingSettings extends InstrumentedFragment implements HelpResourceProvider {
|
public class WifiCallingSettings extends SettingsPreferenceFragment
|
||||||
|
implements HelpResourceProvider {
|
||||||
private static final String TAG = "WifiCallingSettings";
|
private static final String TAG = "WifiCallingSettings";
|
||||||
private int mConstructionSubId;
|
private int mConstructionSubId;
|
||||||
private List<SubscriptionInfo> mSil;
|
private List<SubscriptionInfo> mSil;
|
||||||
@@ -317,17 +317,7 @@ public class WifiCallingSettings extends InstrumentedFragment implements HelpRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
// close this fragment
|
// close this fragment
|
||||||
finish();
|
finishFragment();
|
||||||
}
|
|
||||||
|
|
||||||
protected void finish() {
|
|
||||||
FragmentActivity activity = getActivity();
|
|
||||||
if (activity == null) return;
|
|
||||||
if (getFragmentManager().getBackStackEntryCount() > 0) {
|
|
||||||
getFragmentManager().popBackStack();
|
|
||||||
} else {
|
|
||||||
activity.finish();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int [] subscriptionIdList(List<SubscriptionInfo> subInfoList) {
|
protected int [] subscriptionIdList(List<SubscriptionInfo> subInfoList) {
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import android.content.res.Resources;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.PersistableBundle;
|
import android.os.PersistableBundle;
|
||||||
import android.telephony.CarrierConfigManager;
|
import android.telephony.CarrierConfigManager;
|
||||||
import android.telephony.PhoneStateListener;
|
|
||||||
import android.telephony.SubscriptionManager;
|
import android.telephony.SubscriptionManager;
|
||||||
import android.telephony.TelephonyCallback;
|
import android.telephony.TelephonyCallback;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
@@ -40,7 +39,6 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Switch;
|
import android.widget.Switch;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
@@ -56,8 +54,7 @@ import com.android.settings.SettingsPreferenceFragment;
|
|||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.core.SubSettingLauncher;
|
import com.android.settings.core.SubSettingLauncher;
|
||||||
import com.android.settings.network.ims.WifiCallingQueryImsState;
|
import com.android.settings.network.ims.WifiCallingQueryImsState;
|
||||||
import com.android.settings.widget.SettingsMainSwitchBar;
|
import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||||
import com.android.settings.wifi.calling.LinkifyDescriptionPreference;
|
|
||||||
import com.android.settingslib.widget.OnMainSwitchChangeListener;
|
import com.android.settingslib.widget.OnMainSwitchChangeListener;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -72,6 +69,7 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
|||||||
private static final String TAG = "WifiCallingForSub";
|
private static final String TAG = "WifiCallingForSub";
|
||||||
|
|
||||||
//String keys for preference lookup
|
//String keys for preference lookup
|
||||||
|
private static final String SWITCH_BAR = "wifi_calling_switch_bar";
|
||||||
private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
|
private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
|
||||||
private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
|
private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
|
||||||
private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key";
|
private static final String PREFERENCE_EMERGENCY_ADDRESS = "emergency_address_key";
|
||||||
@@ -91,7 +89,7 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
|||||||
public static final int LAUCH_APP_UPDATE = 1;
|
public static final int LAUCH_APP_UPDATE = 1;
|
||||||
|
|
||||||
//UI objects
|
//UI objects
|
||||||
private SettingsMainSwitchBar mSwitchBar;
|
private SettingsMainSwitchPreference mSwitchBar;
|
||||||
private ListWithEntrySummaryPreference mButtonWfcMode;
|
private ListWithEntrySummaryPreference mButtonWfcMode;
|
||||||
private ListWithEntrySummaryPreference mButtonWfcRoamingMode;
|
private ListWithEntrySummaryPreference mButtonWfcRoamingMode;
|
||||||
private Preference mUpdateAddress;
|
private Preference mUpdateAddress;
|
||||||
@@ -119,23 +117,37 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
|||||||
@Override
|
@Override
|
||||||
public void onCallStateChanged(int state) {
|
public void onCallStateChanged(int state) {
|
||||||
final SettingsActivity activity = (SettingsActivity) getActivity();
|
final SettingsActivity activity = (SettingsActivity) getActivity();
|
||||||
final boolean isNonTtyOrTtyOnVolteEnabled =
|
|
||||||
queryImsState(WifiCallingSettingsForSub.this.mSubId).isAllowUserControl();
|
boolean isWfcEnabled = false;
|
||||||
final boolean isWfcEnabled = mSwitchBar.isChecked()
|
boolean isCallStateIdle = false;
|
||||||
&& isNonTtyOrTtyOnVolteEnabled;
|
|
||||||
boolean isCallStateIdle = getTelephonyManagerForSub(
|
final SettingsMainSwitchPreference prefSwitch = (SettingsMainSwitchPreference)
|
||||||
|
getPreferenceScreen().findPreference(SWITCH_BAR);
|
||||||
|
if (prefSwitch != null) {
|
||||||
|
isWfcEnabled = prefSwitch.isChecked();
|
||||||
|
isCallStateIdle = getTelephonyManagerForSub(
|
||||||
WifiCallingSettingsForSub.this.mSubId).getCallState()
|
WifiCallingSettingsForSub.this.mSubId).getCallState()
|
||||||
== TelephonyManager.CALL_STATE_IDLE;
|
== TelephonyManager.CALL_STATE_IDLE;
|
||||||
mSwitchBar.setEnabled(isCallStateIdle
|
|
||||||
&& isNonTtyOrTtyOnVolteEnabled);
|
boolean isNonTtyOrTtyOnVolteEnabled = true;
|
||||||
|
if (isWfcEnabled || isCallStateIdle) {
|
||||||
|
isNonTtyOrTtyOnVolteEnabled =
|
||||||
|
queryImsState(WifiCallingSettingsForSub.this.mSubId)
|
||||||
|
.isAllowUserControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
isWfcEnabled = isWfcEnabled && isNonTtyOrTtyOnVolteEnabled;
|
||||||
|
prefSwitch.setEnabled(isCallStateIdle && isNonTtyOrTtyOnVolteEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
boolean isWfcModeEditable = true;
|
boolean isWfcModeEditable = true;
|
||||||
boolean isWfcRoamingModeEditable = false;
|
boolean isWfcRoamingModeEditable = false;
|
||||||
|
if (isWfcEnabled && isCallStateIdle) {
|
||||||
final CarrierConfigManager configManager = (CarrierConfigManager)
|
final CarrierConfigManager configManager = (CarrierConfigManager)
|
||||||
activity.getSystemService(Context.CARRIER_CONFIG_SERVICE);
|
activity.getSystemService(Context.CARRIER_CONFIG_SERVICE);
|
||||||
if (configManager != null) {
|
if (configManager != null) {
|
||||||
PersistableBundle b =
|
PersistableBundle b = configManager.getConfigForSubId(
|
||||||
configManager.getConfigForSubId(WifiCallingSettingsForSub.this.mSubId);
|
WifiCallingSettingsForSub.this.mSubId);
|
||||||
if (b != null) {
|
if (b != null) {
|
||||||
isWfcModeEditable = b.getBoolean(
|
isWfcModeEditable = b.getBoolean(
|
||||||
CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
|
CarrierConfigManager.KEY_EDITABLE_WFC_MODE_BOOL);
|
||||||
@@ -143,17 +155,19 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
|||||||
CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
|
CarrierConfigManager.KEY_EDITABLE_WFC_ROAMING_MODE_BOOL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
isWfcModeEditable = false;
|
||||||
|
isWfcRoamingModeEditable = false;
|
||||||
|
}
|
||||||
|
|
||||||
final Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE);
|
final Preference pref = getPreferenceScreen().findPreference(BUTTON_WFC_MODE);
|
||||||
if (pref != null) {
|
if (pref != null) {
|
||||||
pref.setEnabled(isWfcEnabled && isWfcModeEditable
|
pref.setEnabled(isWfcModeEditable);
|
||||||
&& isCallStateIdle);
|
|
||||||
}
|
}
|
||||||
final Preference pref_roam =
|
final Preference pref_roam =
|
||||||
getPreferenceScreen().findPreference(BUTTON_WFC_ROAMING_MODE);
|
getPreferenceScreen().findPreference(BUTTON_WFC_ROAMING_MODE);
|
||||||
if (pref_roam != null) {
|
if (pref_roam != null) {
|
||||||
pref_roam.setEnabled(isWfcEnabled && isWfcRoamingModeEditable
|
pref_roam.setEnabled(isWfcRoamingModeEditable);
|
||||||
&& isCallStateIdle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,20 +198,6 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onActivityCreated(Bundle savedInstanceState) {
|
|
||||||
super.onActivityCreated(savedInstanceState);
|
|
||||||
|
|
||||||
mSwitchBar = getView().findViewById(R.id.switch_bar);
|
|
||||||
mSwitchBar.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroyView() {
|
|
||||||
super.onDestroyView();
|
|
||||||
mSwitchBar.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void showAlert(Intent intent) {
|
void showAlert(Intent intent) {
|
||||||
final Context context = getActivity();
|
final Context context = getActivity();
|
||||||
@@ -292,6 +292,8 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
|
|||||||
mProvisioningManager = getImsProvisioningManager();
|
mProvisioningManager = getImsProvisioningManager();
|
||||||
mImsMmTelManager = getImsMmTelManager();
|
mImsMmTelManager = getImsMmTelManager();
|
||||||
|
|
||||||
|
mSwitchBar = (SettingsMainSwitchPreference) findPreference(SWITCH_BAR);
|
||||||
|
|
||||||
mButtonWfcMode = findPreference(BUTTON_WFC_MODE);
|
mButtonWfcMode = findPreference(BUTTON_WFC_MODE);
|
||||||
mButtonWfcMode.setOnPreferenceChangeListener(this);
|
mButtonWfcMode.setOnPreferenceChangeListener(this);
|
||||||
|
|
||||||
|
|||||||
@@ -522,7 +522,7 @@ public class WifiP2pSettings extends DashboardFragment
|
|||||||
final LayoutInflater layoutInflater = LayoutInflater.from(getPrefContext());
|
final LayoutInflater layoutInflater = LayoutInflater.from(getPrefContext());
|
||||||
final View root = layoutInflater.inflate(R.layout.dialog_edittext, null /* root */);
|
final View root = layoutInflater.inflate(R.layout.dialog_edittext, null /* root */);
|
||||||
mDeviceNameText = root.findViewById(R.id.edittext);
|
mDeviceNameText = root.findViewById(R.id.edittext);
|
||||||
mDeviceNameText.setFilters(new InputFilter[] {new InputFilter.LengthFilter(30)});
|
mDeviceNameText.setFilters(new InputFilter[] {new InputFilter.LengthFilter(22)});
|
||||||
if (mSavedDeviceName != null) {
|
if (mSavedDeviceName != null) {
|
||||||
mDeviceNameText.setText(mSavedDeviceName);
|
mDeviceNameText.setText(mSavedDeviceName);
|
||||||
mDeviceNameText.setSelection(mSavedDeviceName.length());
|
mDeviceNameText.setSelection(mSavedDeviceName.length());
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ public class TetherService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void disableTethering(final int tetheringType) {
|
private void disableTethering(final int tetheringType) {
|
||||||
|
Log.w(TAG, "Disable tethering, type:" + tetheringType);
|
||||||
final TetheringManager tm = (TetheringManager) getSystemService(Context.TETHERING_SERVICE);
|
final TetheringManager tm = (TetheringManager) getSystemService(Context.TETHERING_SERVICE);
|
||||||
tm.stopTethering(tetheringType);
|
tm.stopTethering(tetheringType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import android.net.ConnectivityManager;
|
|||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.util.Log;
|
||||||
import android.widget.Switch;
|
import android.widget.Switch;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
@@ -47,6 +48,8 @@ import com.android.settingslib.widget.OnMainSwitchChangeListener;
|
|||||||
*/
|
*/
|
||||||
public class WifiTetherSwitchBarController implements
|
public class WifiTetherSwitchBarController implements
|
||||||
LifecycleObserver, OnStart, OnStop, DataSaverBackend.Listener, OnMainSwitchChangeListener {
|
LifecycleObserver, OnStart, OnStop, DataSaverBackend.Listener, OnMainSwitchChangeListener {
|
||||||
|
|
||||||
|
private static final String TAG = "WifiTetherSBC";
|
||||||
private static final IntentFilter WIFI_INTENT_FILTER;
|
private static final IntentFilter WIFI_INTENT_FILTER;
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
@@ -63,8 +66,8 @@ public class WifiTetherSwitchBarController implements
|
|||||||
@Override
|
@Override
|
||||||
public void onTetheringFailed() {
|
public void onTetheringFailed() {
|
||||||
super.onTetheringFailed();
|
super.onTetheringFailed();
|
||||||
mSwitchBar.setChecked(false);
|
Log.e(TAG, "Failed to start Wi-Fi Tethering.");
|
||||||
updateWifiSwitch();
|
handleWifiApStateChanged(mWifiManager.getWifiApState());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -111,16 +114,28 @@ public class WifiTetherSwitchBarController implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
void stopTether() {
|
void stopTether() {
|
||||||
|
if (!isWifiApActivated()) return;
|
||||||
|
|
||||||
mSwitchBar.setEnabled(false);
|
mSwitchBar.setEnabled(false);
|
||||||
mConnectivityManager.stopTethering(TETHERING_WIFI);
|
mConnectivityManager.stopTethering(TETHERING_WIFI);
|
||||||
}
|
}
|
||||||
|
|
||||||
void startTether() {
|
void startTether() {
|
||||||
|
if (isWifiApActivated()) return;
|
||||||
|
|
||||||
mSwitchBar.setEnabled(false);
|
mSwitchBar.setEnabled(false);
|
||||||
mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
|
mConnectivityManager.startTethering(TETHERING_WIFI, true /* showProvisioningUi */,
|
||||||
mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
|
mOnStartTetheringCallback, new Handler(Looper.getMainLooper()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isWifiApActivated() {
|
||||||
|
final int wifiApState = mWifiManager.getWifiApState();
|
||||||
|
if (wifiApState == WIFI_AP_STATE_ENABLED || wifiApState == WIFI_AP_STATE_ENABLING) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package com.android.settings.accessibility;
|
package com.android.settings.accessibility;
|
||||||
|
|
||||||
|
import static com.android.settings.accessibility.TextReadingPreferenceFragment.RESET_KEY;
|
||||||
|
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
@@ -25,6 +27,7 @@ import android.content.Context;
|
|||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settingslib.widget.LayoutPreference;
|
||||||
|
|
||||||
import com.google.android.setupdesign.GlifPreferenceLayout;
|
import com.google.android.setupdesign.GlifPreferenceLayout;
|
||||||
|
|
||||||
@@ -51,6 +54,9 @@ public class TextReadingPreferenceFragmentForSetupWizardTest {
|
|||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
mFragment = spy(new TextReadingPreferenceFragmentForSetupWizard());
|
mFragment = spy(new TextReadingPreferenceFragmentForSetupWizard());
|
||||||
|
final LayoutPreference resetPreference =
|
||||||
|
new LayoutPreference(mContext, R.layout.accessibility_text_reading_reset_button);
|
||||||
|
doReturn(resetPreference).when(mFragment).findPreference(RESET_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ import org.robolectric.RuntimeEnvironment;
|
|||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class BluetoothFeatureProviderImplTest {
|
public class BluetoothFeatureProviderImplTest {
|
||||||
private static final String SETTINGS_URI = "content://test.provider/settings_uri";
|
private static final String SETTINGS_URI = "content://test.provider/settings_uri";
|
||||||
|
private static final String CONTROL_METADATA =
|
||||||
|
"<HEARABLE_CONTROL_SLICE_WITH_WIDTH>" + SETTINGS_URI
|
||||||
|
+ "</HEARABLE_CONTROL_SLICE_WITH_WIDTH>";
|
||||||
|
private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
|
||||||
|
|
||||||
private BluetoothFeatureProvider mBluetoothFeatureProvider;
|
private BluetoothFeatureProvider mBluetoothFeatureProvider;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
@@ -54,4 +59,13 @@ public class BluetoothFeatureProviderImplTest {
|
|||||||
final Uri uri = mBluetoothFeatureProvider.getBluetoothDeviceSettingsUri(mBluetoothDevice);
|
final Uri uri = mBluetoothFeatureProvider.getBluetoothDeviceSettingsUri(mBluetoothDevice);
|
||||||
assertThat(uri.toString()).isEqualTo(SETTINGS_URI);
|
assertThat(uri.toString()).isEqualTo(SETTINGS_URI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getBluetoothDeviceControlUri_returnsCorrectUri() {
|
||||||
|
when(mBluetoothDevice.getMetadata(METADATA_FAST_PAIR_CUSTOMIZED_FIELDS)).thenReturn(
|
||||||
|
CONTROL_METADATA.getBytes());
|
||||||
|
assertThat(
|
||||||
|
mBluetoothFeatureProvider.getBluetoothDeviceControlUri(mBluetoothDevice)).isEqualTo(
|
||||||
|
SETTINGS_URI);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ public class DataUsageListTest {
|
|||||||
mMobileDataEnabledListener);
|
mMobileDataEnabledListener);
|
||||||
ReflectionHelpers.setField(mDataUsageList, "services", mNetworkServices);
|
ReflectionHelpers.setField(mDataUsageList, "services", mNetworkServices);
|
||||||
doReturn(mLoaderManager).when(mDataUsageList).getLoaderManager();
|
doReturn(mLoaderManager).when(mDataUsageList).getLoaderManager();
|
||||||
|
mDataUsageList.mLoadingViewController = mock(LoadingViewController.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -207,8 +208,6 @@ public class DataUsageListTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onLoadFinished_networkCycleDataCallback_shouldShowCycleSpinner() {
|
public void onLoadFinished_networkCycleDataCallback_shouldShowCycleSpinner() {
|
||||||
final LoadingViewController loadingViewController = mock(LoadingViewController.class);
|
|
||||||
mDataUsageList.mLoadingViewController = loadingViewController;
|
|
||||||
final Spinner spinner = getSpinner(getHeader());
|
final Spinner spinner = getSpinner(getHeader());
|
||||||
spinner.setVisibility(View.INVISIBLE);
|
spinner.setVisibility(View.INVISIBLE);
|
||||||
mDataUsageList.mCycleSpinner = spinner;
|
mDataUsageList.mCycleSpinner = spinner;
|
||||||
|
|||||||
@@ -16,16 +16,75 @@
|
|||||||
|
|
||||||
package com.android.settings.wifi;
|
package com.android.settings.wifi;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.text.TextUtils;
|
||||||
|
|
||||||
|
import com.android.settings.testutils.shadow.ShadowUtils;
|
||||||
|
import com.android.settingslib.wifi.WifiPermissionChecker;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnit;
|
||||||
|
import org.mockito.junit.MockitoRule;
|
||||||
import org.robolectric.Robolectric;
|
import org.robolectric.Robolectric;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.annotation.Config;
|
||||||
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
@Config(shadows = {ShadowUtils.class})
|
||||||
public class WifiScanModeActivityTest {
|
public class WifiScanModeActivityTest {
|
||||||
|
|
||||||
|
static final String LAUNCHED_PACKAGE = "launched_package";
|
||||||
|
static final String APP_LABEL = "app_label";
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
|
||||||
|
@Mock
|
||||||
|
WifiPermissionChecker mWifiPermissionChecker;
|
||||||
|
|
||||||
|
WifiScanModeActivity mActivity;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
mActivity = spy(Robolectric.setupActivity(WifiScanModeActivity.class));
|
||||||
|
mActivity.mWifiPermissionChecker = mWifiPermissionChecker;
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
ShadowUtils.reset();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void launchActivity_noIntentAction_shouldNotFatalException() {
|
public void launchActivity_noIntentAction_shouldNotFatalException() {
|
||||||
WifiScanModeActivity wifiScanModeActivity =
|
WifiScanModeActivity wifiScanModeActivity =
|
||||||
Robolectric.setupActivity(WifiScanModeActivity.class);
|
Robolectric.setupActivity(WifiScanModeActivity.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void refreshAppLabel_noPackageName_shouldNotFatalException() {
|
||||||
|
when(mWifiPermissionChecker.getLaunchedPackage()).thenReturn(null);
|
||||||
|
|
||||||
|
mActivity.refreshAppLabel();
|
||||||
|
|
||||||
|
assertThat(TextUtils.isEmpty(mActivity.mApp)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void refreshAppLabel_hasPackageName_shouldHasAppLabel() {
|
||||||
|
ShadowUtils.setApplicationLabel(LAUNCHED_PACKAGE, APP_LABEL);
|
||||||
|
when(mWifiPermissionChecker.getLaunchedPackage()).thenReturn(LAUNCHED_PACKAGE);
|
||||||
|
|
||||||
|
mActivity.refreshAppLabel();
|
||||||
|
|
||||||
|
assertThat(mActivity.mApp).isEqualTo(APP_LABEL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ import com.android.settings.network.ims.MockWifiCallingQueryImsState;
|
|||||||
import com.android.settings.network.ims.WifiCallingQueryImsState;
|
import com.android.settings.network.ims.WifiCallingQueryImsState;
|
||||||
import com.android.settings.testutils.shadow.ShadowFragment;
|
import com.android.settings.testutils.shadow.ShadowFragment;
|
||||||
import com.android.settings.widget.SettingsMainSwitchBar;
|
import com.android.settings.widget.SettingsMainSwitchBar;
|
||||||
|
import com.android.settings.widget.SettingsMainSwitchPreference;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -72,6 +73,7 @@ import org.robolectric.util.ReflectionHelpers;
|
|||||||
public class WifiCallingSettingsForSubTest {
|
public class WifiCallingSettingsForSubTest {
|
||||||
private static final int SUB_ID = 2;
|
private static final int SUB_ID = 2;
|
||||||
|
|
||||||
|
private static final String SWITCH_BAR = "wifi_calling_switch_bar";
|
||||||
private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
|
private static final String BUTTON_WFC_MODE = "wifi_calling_mode";
|
||||||
private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
|
private static final String BUTTON_WFC_ROAMING_MODE = "wifi_calling_roaming_mode";
|
||||||
private static final String PREFERENCE_NO_OPTIONS_DESC = "no_options_description";
|
private static final String PREFERENCE_NO_OPTIONS_DESC = "no_options_description";
|
||||||
@@ -100,6 +102,8 @@ public class WifiCallingSettingsForSubTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private View mView;
|
private View mView;
|
||||||
@Mock
|
@Mock
|
||||||
|
private SettingsMainSwitchPreference mSwitchBarPreference;
|
||||||
|
@Mock
|
||||||
private LinkifyDescriptionPreference mDescriptionView;
|
private LinkifyDescriptionPreference mDescriptionView;
|
||||||
@Mock
|
@Mock
|
||||||
private ListWithEntrySummaryPreference mButtonWfcMode;
|
private ListWithEntrySummaryPreference mButtonWfcMode;
|
||||||
@@ -116,6 +120,7 @@ public class WifiCallingSettingsForSubTest {
|
|||||||
doReturn(mContext.getTheme()).when(mActivity).getTheme();
|
doReturn(mContext.getTheme()).when(mActivity).getTheme();
|
||||||
|
|
||||||
mFragment = spy(new TestFragment());
|
mFragment = spy(new TestFragment());
|
||||||
|
mFragment.setSwitchBar(mSwitchBarPreference);
|
||||||
doReturn(mActivity).when(mFragment).getActivity();
|
doReturn(mActivity).when(mFragment).getActivity();
|
||||||
doReturn(mContext).when(mFragment).getContext();
|
doReturn(mContext).when(mFragment).getContext();
|
||||||
doReturn(mock(Intent.class)).when(mActivity).getIntent();
|
doReturn(mock(Intent.class)).when(mActivity).getIntent();
|
||||||
@@ -125,10 +130,6 @@ public class WifiCallingSettingsForSubTest {
|
|||||||
final Bundle bundle = new Bundle();
|
final Bundle bundle = new Bundle();
|
||||||
when(mFragment.getArguments()).thenReturn(bundle);
|
when(mFragment.getArguments()).thenReturn(bundle);
|
||||||
doNothing().when(mFragment).addPreferencesFromResource(anyInt());
|
doNothing().when(mFragment).addPreferencesFromResource(anyInt());
|
||||||
doReturn(mock(ListWithEntrySummaryPreference.class)).when(mFragment).findPreference(any());
|
|
||||||
doReturn(mButtonWfcMode).when(mFragment).findPreference(BUTTON_WFC_MODE);
|
|
||||||
doReturn(mButtonWfcRoamingMode).when(mFragment).findPreference(BUTTON_WFC_ROAMING_MODE);
|
|
||||||
doReturn(mDescriptionView).when(mFragment).findPreference(PREFERENCE_NO_OPTIONS_DESC);
|
|
||||||
doNothing().when(mFragment).finish();
|
doNothing().when(mFragment).finish();
|
||||||
doReturn(mView).when(mFragment).getView();
|
doReturn(mView).when(mFragment).getView();
|
||||||
|
|
||||||
@@ -344,6 +345,29 @@ public class WifiCallingSettingsForSubTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected class TestFragment extends WifiCallingSettingsForSub {
|
protected class TestFragment extends WifiCallingSettingsForSub {
|
||||||
|
private SettingsMainSwitchPreference mSwitchPref;
|
||||||
|
|
||||||
|
protected void setSwitchBar(SettingsMainSwitchPreference switchPref) {
|
||||||
|
mSwitchPref = switchPref;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends Preference> T findPreference(CharSequence key) {
|
||||||
|
if (SWITCH_BAR.equals(key)) {
|
||||||
|
return (T) mSwitchPref;
|
||||||
|
}
|
||||||
|
if (BUTTON_WFC_MODE.equals(key)) {
|
||||||
|
return (T) mButtonWfcMode;
|
||||||
|
}
|
||||||
|
if (BUTTON_WFC_ROAMING_MODE.equals(key)) {
|
||||||
|
return (T) mButtonWfcRoamingMode;
|
||||||
|
}
|
||||||
|
if (PREFERENCE_NO_OPTIONS_DESC.equals(key)) {
|
||||||
|
return (T) mDescriptionView;
|
||||||
|
}
|
||||||
|
return (T) mock(ListWithEntrySummaryPreference.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object getSystemService(final String name) {
|
protected Object getSystemService(final String name) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
|
|||||||
@@ -83,8 +83,45 @@ public class WifiTetherSwitchBarControllerTest {
|
|||||||
mController.mDataSaverBackend = mDataSaverBackend;
|
mController.mDataSaverBackend = mDataSaverBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void startTether_wifiApIsActivated_doNothing() {
|
||||||
|
when(mWifiManager.getWifiApState()).thenReturn(WIFI_AP_STATE_ENABLED);
|
||||||
|
|
||||||
|
mController.startTether();
|
||||||
|
|
||||||
|
verify(mConnectivityManager, never()).startTethering(anyInt(), anyBoolean(), any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void startTether_wifiApNotActivated_startTethering() {
|
||||||
|
when(mWifiManager.getWifiApState()).thenReturn(WIFI_AP_STATE_DISABLED);
|
||||||
|
|
||||||
|
mController.startTether();
|
||||||
|
|
||||||
|
verify(mConnectivityManager).startTethering(anyInt(), anyBoolean(), any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void stopTether_wifiApIsActivated_stopTethering() {
|
||||||
|
when(mWifiManager.getWifiApState()).thenReturn(WIFI_AP_STATE_ENABLED);
|
||||||
|
|
||||||
|
mController.stopTether();
|
||||||
|
|
||||||
|
verify(mConnectivityManager).stopTethering(anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void stopTether_wifiApNotActivated_doNothing() {
|
||||||
|
when(mWifiManager.getWifiApState()).thenReturn(WIFI_AP_STATE_DISABLED);
|
||||||
|
|
||||||
|
mController.stopTether();
|
||||||
|
|
||||||
|
verify(mConnectivityManager, never()).stopTethering(anyInt());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void startTether_fail_resetSwitchBar() {
|
public void startTether_fail_resetSwitchBar() {
|
||||||
|
when(mWifiManager.getWifiApState()).thenReturn(WIFI_AP_STATE_DISABLED);
|
||||||
when(mDataSaverBackend.isDataSaverEnabled()).thenReturn(false);
|
when(mDataSaverBackend.isDataSaverEnabled()).thenReturn(false);
|
||||||
|
|
||||||
mController.startTether();
|
mController.startTether();
|
||||||
@@ -130,6 +167,7 @@ public class WifiTetherSwitchBarControllerTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onSwitchChanged_isNotChecked_stopTethering() {
|
public void onSwitchChanged_isNotChecked_stopTethering() {
|
||||||
|
when(mWifiManager.getWifiApState()).thenReturn(WIFI_AP_STATE_ENABLED);
|
||||||
when(mSwitch.isChecked()).thenReturn(false);
|
when(mSwitch.isChecked()).thenReturn(false);
|
||||||
|
|
||||||
mController.onSwitchChanged(mSwitch, mSwitch.isChecked());
|
mController.onSwitchChanged(mSwitch, mSwitch.isChecked());
|
||||||
|
|||||||
@@ -44,54 +44,79 @@ import org.mockito.MockitoAnnotations;
|
|||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class PrivacyDashboardActivityTest {
|
public class PrivacyDashboardActivityTest {
|
||||||
|
|
||||||
private static final String DEFAULT_FRAGMENT_CLASSNAME = "DefaultFragmentClassname";
|
private static final String DEFAULT_FRAGMENT_CLASSNAME = "DefaultFragmentClassname";
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
|
private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
|
||||||
private Settings.PrivacyDashboardActivity mActivity;
|
private Settings.PrivacyDashboardActivity mActivity;
|
||||||
|
private static final String ACTION_PRIVACY_ADVANCED_SETTINGS =
|
||||||
|
"android.settings.PRIVACY_ADVANCED_SETTINGS";
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onCreate_whenSafetyCenterEnabled_redirectsToSafetyCenter() throws Exception {
|
||||||
|
startActivityUsingIntent(android.provider.Settings.ACTION_PRIVACY_SETTINGS);
|
||||||
|
when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true);
|
||||||
|
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||||
|
mActivity.handleSafetyCenterRedirection();
|
||||||
|
verify(mActivity).startActivity(intentCaptor.capture());
|
||||||
|
assertThat(intentCaptor.getValue().getAction()).isEqualTo(Intent.ACTION_SAFETY_CENTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onCreateWithAdvancedIntent_whenSafetyCenterEnabled_doesntRedirectToSafetyCenter()
|
||||||
|
throws Exception {
|
||||||
|
startActivityUsingIntent(ACTION_PRIVACY_ADVANCED_SETTINGS);
|
||||||
|
when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true);
|
||||||
|
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||||
|
mActivity.handleSafetyCenterRedirection();
|
||||||
|
verify(mActivity, times(0)).startActivity(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onCreate_whenSafetyCenterDisabled_doesntRedirectToSafetyCenter() throws Exception {
|
||||||
|
startActivityUsingIntent(android.provider.Settings.ACTION_PRIVACY_SETTINGS);
|
||||||
|
when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(false);
|
||||||
|
mActivity.handleSafetyCenterRedirection();
|
||||||
|
verify(mActivity, times(0)).startActivity(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onCreateWithAdvancedIntent_whenSafetyCenterDisabled_doesntRedirectToSafetyCenter()
|
||||||
|
throws Exception {
|
||||||
|
startActivityUsingIntent(ACTION_PRIVACY_ADVANCED_SETTINGS);
|
||||||
|
when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true);
|
||||||
|
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
||||||
|
mActivity.handleSafetyCenterRedirection();
|
||||||
|
verify(mActivity, times(0)).startActivity(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startActivityUsingIntent(String intentAction) throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
|
SafetyCenterManagerWrapper.sInstance = mSafetyCenterManagerWrapper;
|
||||||
final Intent intent = new Intent();
|
final Intent intent = new Intent();
|
||||||
intent.setAction(android.provider.Settings.ACTION_PRIVACY_SETTINGS);
|
intent.setAction(intentAction);
|
||||||
intent.setClass(InstrumentationRegistry.getInstrumentation().getTargetContext(),
|
intent.setClass(InstrumentationRegistry.getInstrumentation().getTargetContext(),
|
||||||
Settings.PrivacyDashboardActivity.class);
|
Settings.PrivacyDashboardActivity.class);
|
||||||
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, DEFAULT_FRAGMENT_CLASSNAME);
|
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, DEFAULT_FRAGMENT_CLASSNAME);
|
||||||
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
|
||||||
try {
|
try {
|
||||||
mActivity =
|
Settings.PrivacyDashboardActivity activity =
|
||||||
spy((Settings.PrivacyDashboardActivity) InstrumentationRegistry
|
(Settings.PrivacyDashboardActivity) InstrumentationRegistry
|
||||||
.getInstrumentation().newActivity(
|
.getInstrumentation().newActivity(
|
||||||
getClass().getClassLoader(),
|
getClass().getClassLoader(),
|
||||||
Settings.PrivacyDashboardActivity.class.getName(),
|
Settings.PrivacyDashboardActivity.class.getName(),
|
||||||
intent));
|
intent);
|
||||||
|
activity.setIntent(intent);
|
||||||
|
mActivity = spy(activity);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e); // nothing to do
|
throw new RuntimeException(e); // nothing to do
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
doNothing().when(mActivity).startActivity(any(Intent.class));
|
doNothing().when(mActivity).startActivity(any(Intent.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onCreate_whenSafetyCenterEnabled_redirectsToSafetyCenter() {
|
|
||||||
when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(true);
|
|
||||||
final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
|
|
||||||
|
|
||||||
mActivity.handleSafetyCenterRedirection();
|
|
||||||
|
|
||||||
verify(mActivity).startActivity(intentCaptor.capture());
|
|
||||||
assertThat(intentCaptor.getValue().getAction()).isEqualTo(Intent.ACTION_SAFETY_CENTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onCreate_whenSafetyCenterDisabled_doesntRedirectToSafetyCenter() {
|
|
||||||
when(mSafetyCenterManagerWrapper.isEnabled(any(Context.class))).thenReturn(false);
|
|
||||||
mActivity.handleSafetyCenterRedirection();
|
|
||||||
|
|
||||||
verify(mActivity, times(0)).startActivity(any());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,13 +54,13 @@ import java.util.List;
|
|||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class SafetySourceBroadcastReceiverTest {
|
public class SafetySourceBroadcastReceiverTest {
|
||||||
|
|
||||||
|
private static final String REFRESH_BROADCAST_ID = "REFRESH_BROADCAST_ID";
|
||||||
|
|
||||||
private Context mApplicationContext;
|
private Context mApplicationContext;
|
||||||
|
|
||||||
@Mock
|
@Mock private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
|
||||||
private SafetyCenterManagerWrapper mSafetyCenterManagerWrapper;
|
|
||||||
|
|
||||||
@Mock
|
@Mock private LockPatternUtils mLockPatternUtils;
|
||||||
private LockPatternUtils mLockPatternUtils;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
@@ -77,17 +77,6 @@ public class SafetySourceBroadcastReceiverTest {
|
|||||||
SafetyCenterManagerWrapper.sInstance = null;
|
SafetyCenterManagerWrapper.sInstance = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void onReceive_onRefresh_whenSafetyCenterIsEnabled_withNoIntentAction_doesNotSetData() {
|
|
||||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
|
||||||
Intent intent = new Intent().putExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS, new String[]{});
|
|
||||||
|
|
||||||
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
|
||||||
|
|
||||||
verify(mSafetyCenterManagerWrapper, never()).setSafetySourceData(
|
|
||||||
any(), any(), any(), any());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onReceive_onRefresh_whenSafetyCenterIsDisabled_doesNotSetData() {
|
public void onReceive_onRefresh_whenSafetyCenterIsDisabled_doesNotSetData() {
|
||||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
|
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(false);
|
||||||
@@ -96,23 +85,43 @@ public class SafetySourceBroadcastReceiverTest {
|
|||||||
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
||||||
.putExtra(
|
.putExtra(
|
||||||
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
|
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
|
||||||
new String[]{ LockScreenSafetySource.SAFETY_SOURCE_ID });
|
new String[] {LockScreenSafetySource.SAFETY_SOURCE_ID})
|
||||||
|
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_BROADCAST_ID);
|
||||||
|
|
||||||
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||||
|
|
||||||
verify(mSafetyCenterManagerWrapper, never()).setSafetySourceData(
|
verify(mSafetyCenterManagerWrapper, never())
|
||||||
any(), any(), any(), any());
|
.setSafetySourceData(any(), any(), any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onReceive_onRefresh_whenSafetyCenterIsEnabled_withNoIntentAction_doesNotSetData() {
|
||||||
|
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||||
|
Intent intent =
|
||||||
|
new Intent()
|
||||||
|
.putExtra(
|
||||||
|
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
|
||||||
|
new String[] {LockScreenSafetySource.SAFETY_SOURCE_ID})
|
||||||
|
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_BROADCAST_ID);
|
||||||
|
|
||||||
|
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||||
|
|
||||||
|
verify(mSafetyCenterManagerWrapper, never())
|
||||||
|
.setSafetySourceData(any(), any(), any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void onReceive_onRefresh_whenSafetyCenterIsEnabled_withNullSourceIds_doesNotSetData() {
|
public void onReceive_onRefresh_whenSafetyCenterIsEnabled_withNullSourceIds_doesNotSetData() {
|
||||||
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
when(mSafetyCenterManagerWrapper.isEnabled(mApplicationContext)).thenReturn(true);
|
||||||
Intent intent = new Intent().setAction(ACTION_REFRESH_SAFETY_SOURCES);
|
Intent intent =
|
||||||
|
new Intent()
|
||||||
|
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
||||||
|
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_BROADCAST_ID);
|
||||||
|
|
||||||
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||||
|
|
||||||
verify(mSafetyCenterManagerWrapper, never()).setSafetySourceData(
|
verify(mSafetyCenterManagerWrapper, never())
|
||||||
any(), any(), any(), any());
|
.setSafetySourceData(any(), any(), any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -121,12 +130,29 @@ public class SafetySourceBroadcastReceiverTest {
|
|||||||
Intent intent =
|
Intent intent =
|
||||||
new Intent()
|
new Intent()
|
||||||
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
||||||
.putExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS, new String[]{});
|
.putExtra(EXTRA_REFRESH_SAFETY_SOURCE_IDS, new String[] {})
|
||||||
|
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_BROADCAST_ID);
|
||||||
|
|
||||||
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||||
|
|
||||||
verify(mSafetyCenterManagerWrapper, never()).setSafetySourceData(
|
verify(mSafetyCenterManagerWrapper, never())
|
||||||
any(), any(), any(), any());
|
.setSafetySourceData(any(), any(), any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onReceive_onRefresh_whenSafetyCenterIsEnabled_withNoBroadcastId_doesNotSetData() {
|
||||||
|
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});
|
||||||
|
|
||||||
|
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||||
|
|
||||||
|
verify(mSafetyCenterManagerWrapper, never())
|
||||||
|
.setSafetySourceData(any(), any(), any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -137,38 +163,19 @@ public class SafetySourceBroadcastReceiverTest {
|
|||||||
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
||||||
.putExtra(
|
.putExtra(
|
||||||
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
|
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
|
||||||
new String[]{ LockScreenSafetySource.SAFETY_SOURCE_ID });
|
new String[] {LockScreenSafetySource.SAFETY_SOURCE_ID})
|
||||||
|
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_BROADCAST_ID);
|
||||||
|
|
||||||
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||||
ArgumentCaptor<SafetyEvent> captor = ArgumentCaptor.forClass(SafetyEvent.class);
|
ArgumentCaptor<SafetyEvent> captor = ArgumentCaptor.forClass(SafetyEvent.class);
|
||||||
verify(mSafetyCenterManagerWrapper, times(1))
|
verify(mSafetyCenterManagerWrapper, times(1))
|
||||||
.setSafetySourceData(any(), any(), any(), captor.capture());
|
.setSafetySourceData(any(), any(), any(), captor.capture());
|
||||||
|
|
||||||
assertThat(captor.getValue()).isEqualTo(
|
assertThat(captor.getValue())
|
||||||
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED).build());
|
.isEqualTo(
|
||||||
}
|
|
||||||
|
|
||||||
@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)
|
new SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
|
||||||
.setRefreshBroadcastId(refreshBroadcastId).build());
|
.setRefreshBroadcastId(REFRESH_BROADCAST_ID)
|
||||||
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -179,7 +186,8 @@ public class SafetySourceBroadcastReceiverTest {
|
|||||||
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
||||||
.putExtra(
|
.putExtra(
|
||||||
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
|
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
|
||||||
new String[]{ LockScreenSafetySource.SAFETY_SOURCE_ID });
|
new String[] {LockScreenSafetySource.SAFETY_SOURCE_ID})
|
||||||
|
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_BROADCAST_ID);
|
||||||
|
|
||||||
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||||
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
|
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
|
||||||
@@ -197,7 +205,8 @@ public class SafetySourceBroadcastReceiverTest {
|
|||||||
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
.setAction(ACTION_REFRESH_SAFETY_SOURCES)
|
||||||
.putExtra(
|
.putExtra(
|
||||||
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
|
EXTRA_REFRESH_SAFETY_SOURCE_IDS,
|
||||||
new String[]{ BiometricsSafetySource.SAFETY_SOURCE_ID });
|
new String[] {BiometricsSafetySource.SAFETY_SOURCE_ID})
|
||||||
|
.putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_BROADCAST_ID);
|
||||||
|
|
||||||
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
new SafetySourceBroadcastReceiver().onReceive(mApplicationContext, intent);
|
||||||
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
|
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user