summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp28
-rw-r--r--AndroidManifest.xml52
-rw-r--r--NOTICE48
-rw-r--r--proguard.flags5
-rw-r--r--res/drawable-mdpi/ic_settings_qti_feedback.pngbin0 -> 18422 bytes
-rw-r--r--res/drawable-xhdpi/ic_settings_qti_feedback.pngbin0 -> 24692 bytes
-rw-r--r--res/drawable-xxhdpi/ic_settings_qti_feedback.pngbin0 -> 36995 bytes
-rw-r--r--res/drawable-xxxhdpi/ic_settings_qti_feedback.pngbin0 -> 52058 bytes
-rw-r--r--res/drawable/ic_volume_media_bt.xml32
-rw-r--r--res/layout/bluetooth_audio_codec_dialog.xml8
-rw-r--r--res/layout/bluetooth_group_options.xml137
-rw-r--r--res/layout/preference_ba_device_volume_slider.xml108
-rw-r--r--res/layout/select_source_prompt.xml52
-rw-r--r--res/layout/wifi_dialog.xml7
-rw-r--r--res/values-af/arrays.xml1
-rw-r--r--res/values-af/strings.xml3
-rw-r--r--res/values-am/arrays.xml1
-rw-r--r--res/values-am/strings.xml3
-rw-r--r--res/values-ar/arrays.xml1
-rw-r--r--res/values-ar/strings.xml3
-rw-r--r--res/values-az/arrays.xml1
-rw-r--r--res/values-az/strings.xml3
-rw-r--r--res/values-b+sr+Latn/arrays.xml1
-rw-r--r--res/values-b+sr+Latn/strings.xml3
-rw-r--r--res/values-be/arrays.xml1
-rw-r--r--res/values-be/strings.xml3
-rw-r--r--res/values-bg/arrays.xml1
-rw-r--r--res/values-bg/strings.xml5
-rw-r--r--res/values-bn/arrays.xml1
-rw-r--r--res/values-bn/strings.xml3
-rw-r--r--res/values-bs/arrays.xml1
-rw-r--r--res/values-bs/strings.xml3
-rw-r--r--res/values-ca/arrays.xml1
-rw-r--r--res/values-ca/strings.xml3
-rw-r--r--res/values-cs/arrays.xml1
-rw-r--r--res/values-cs/strings.xml3
-rw-r--r--res/values-da/arrays.xml1
-rw-r--r--res/values-da/strings.xml3
-rw-r--r--res/values-de/arrays.xml1
-rw-r--r--res/values-de/strings.xml3
-rw-r--r--res/values-el/arrays.xml1
-rw-r--r--res/values-el/strings.xml3
-rw-r--r--res/values-en-rAU/arrays.xml1
-rw-r--r--res/values-en-rAU/strings.xml3
-rw-r--r--res/values-en-rCA/strings.xml3
-rw-r--r--res/values-en-rGB/arrays.xml1
-rw-r--r--res/values-en-rGB/strings.xml3
-rw-r--r--res/values-en-rIN/arrays.xml1
-rw-r--r--res/values-en-rIN/strings.xml3
-rw-r--r--res/values-en-rXC/strings.xml3
-rw-r--r--res/values-es-rUS/arrays.xml1
-rw-r--r--res/values-es-rUS/strings.xml3
-rw-r--r--res/values-es/arrays.xml1
-rw-r--r--res/values-es/strings.xml5
-rw-r--r--res/values-et/arrays.xml1
-rw-r--r--res/values-et/strings.xml3
-rw-r--r--res/values-eu/arrays.xml1
-rw-r--r--res/values-eu/strings.xml3
-rw-r--r--res/values-fa/arrays.xml1
-rw-r--r--res/values-fa/strings.xml3
-rw-r--r--res/values-fi/arrays.xml1
-rw-r--r--res/values-fi/strings.xml3
-rw-r--r--res/values-fr-rCA/arrays.xml1
-rw-r--r--res/values-fr-rCA/strings.xml3
-rw-r--r--res/values-fr/arrays.xml1
-rw-r--r--res/values-fr/strings.xml3
-rw-r--r--res/values-fr/strings_group.xml53
-rw-r--r--res/values-gl/arrays.xml1
-rw-r--r--res/values-gu/arrays.xml1
-rw-r--r--res/values-gu/strings.xml3
-rw-r--r--res/values-hi/arrays.xml1
-rw-r--r--res/values-hi/strings.xml3
-rw-r--r--res/values-hr/arrays.xml1
-rw-r--r--res/values-hr/strings.xml3
-rw-r--r--res/values-hu/arrays.xml1
-rw-r--r--res/values-hu/strings.xml3
-rw-r--r--res/values-hy/arrays.xml1
-rw-r--r--res/values-hy/strings.xml3
-rw-r--r--res/values-in/arrays.xml1
-rw-r--r--res/values-in/strings.xml3
-rw-r--r--res/values-is/arrays.xml1
-rw-r--r--res/values-is/strings.xml3
-rw-r--r--res/values-it/arrays.xml1
-rw-r--r--res/values-it/strings.xml3
-rw-r--r--res/values-iw/arrays.xml1
-rw-r--r--res/values-iw/strings.xml3
-rw-r--r--res/values-ja/arrays.xml1
-rw-r--r--res/values-ja/strings.xml3
-rw-r--r--res/values-ja/strings_group.xml52
-rw-r--r--res/values-ka/arrays.xml1
-rw-r--r--res/values-ka/strings.xml3
-rw-r--r--res/values-kk/arrays.xml1
-rw-r--r--res/values-kk/strings.xml7
-rw-r--r--res/values-km/arrays.xml1
-rw-r--r--res/values-km/strings.xml3
-rw-r--r--res/values-kn/arrays.xml1
-rw-r--r--res/values-kn/strings.xml3
-rw-r--r--res/values-ko/arrays.xml1
-rw-r--r--res/values-ko/strings.xml3
-rw-r--r--res/values-ko/strings_group.xml53
-rw-r--r--res/values-ky/arrays.xml1
-rw-r--r--res/values-ky/strings.xml3
-rw-r--r--res/values-lo/arrays.xml1
-rw-r--r--res/values-lo/strings.xml3
-rw-r--r--res/values-lt/arrays.xml1
-rw-r--r--res/values-lt/strings.xml3
-rw-r--r--res/values-lv/arrays.xml1
-rw-r--r--res/values-lv/strings.xml3
-rw-r--r--res/values-mk/arrays.xml1
-rw-r--r--res/values-mk/strings.xml5
-rw-r--r--res/values-ml/arrays.xml1
-rw-r--r--res/values-ml/strings.xml3
-rw-r--r--res/values-mn/arrays.xml1
-rw-r--r--res/values-mn/strings.xml3
-rw-r--r--res/values-mr/arrays.xml1
-rw-r--r--res/values-mr/strings.xml3
-rw-r--r--res/values-ms/arrays.xml1
-rw-r--r--res/values-ms/strings.xml3
-rw-r--r--res/values-my/arrays.xml1
-rw-r--r--res/values-my/strings.xml3
-rw-r--r--res/values-nb/arrays.xml1
-rw-r--r--res/values-nb/strings.xml3
-rw-r--r--res/values-ne/arrays.xml1
-rw-r--r--res/values-ne/strings.xml3
-rw-r--r--res/values-nl/arrays.xml1
-rw-r--r--res/values-nl/strings.xml3
-rw-r--r--res/values-or/strings.xml3
-rw-r--r--res/values-pa/arrays.xml1
-rw-r--r--res/values-pa/strings.xml3
-rw-r--r--res/values-pl/arrays.xml1
-rw-r--r--res/values-pl/strings.xml3
-rw-r--r--res/values-pt-rBR/arrays.xml1
-rw-r--r--res/values-pt-rPT/arrays.xml1
-rw-r--r--res/values-pt-rPT/strings.xml3
-rw-r--r--res/values-pt-rPT/strings_group.xml54
-rw-r--r--res/values-pt/arrays.xml1
-rw-r--r--res/values-pt/strings_group.xml54
-rw-r--r--res/values-ro/arrays.xml1
-rw-r--r--res/values-ro/strings.xml3
-rw-r--r--res/values-ru/arrays.xml1
-rw-r--r--res/values-ru/strings.xml3
-rw-r--r--res/values-si/arrays.xml1
-rw-r--r--res/values-si/strings.xml3
-rw-r--r--res/values-sk/arrays.xml1
-rw-r--r--res/values-sk/strings.xml3
-rw-r--r--res/values-sl/arrays.xml1
-rw-r--r--res/values-sl/strings.xml3
-rw-r--r--res/values-sq/arrays.xml1
-rw-r--r--res/values-sq/strings.xml3
-rw-r--r--res/values-sr/arrays.xml1
-rw-r--r--res/values-sr/strings.xml3
-rw-r--r--res/values-sv/arrays.xml1
-rw-r--r--res/values-sv/strings.xml3
-rw-r--r--res/values-sw/arrays.xml1
-rw-r--r--res/values-sw/strings.xml3
-rw-r--r--res/values-ta/arrays.xml1
-rw-r--r--res/values-ta/strings.xml3
-rw-r--r--res/values-te/arrays.xml1
-rw-r--r--res/values-te/strings.xml3
-rw-r--r--res/values-th/arrays.xml1
-rw-r--r--res/values-th/strings.xml3
-rw-r--r--res/values-tl/arrays.xml1
-rw-r--r--res/values-tl/strings.xml3
-rw-r--r--res/values-tr/arrays.xml1
-rw-r--r--res/values-tr/strings.xml3
-rw-r--r--res/values-uk/arrays.xml1
-rw-r--r--res/values-uk/strings.xml3
-rw-r--r--res/values-ur/arrays.xml1
-rw-r--r--res/values-ur/strings.xml3
-rw-r--r--res/values-uz/arrays.xml1
-rw-r--r--res/values-uz/strings.xml3
-rw-r--r--res/values-vi/arrays.xml1
-rw-r--r--res/values-vi/strings.xml3
-rw-r--r--res/values-zh-rCN/arrays.xml7
-rw-r--r--res/values-zh-rCN/strings.xml23
-rw-r--r--res/values-zh-rCN/strings_group.xml53
-rw-r--r--res/values-zh-rHK/arrays.xml1
-rw-r--r--res/values-zh-rHK/strings.xml3
-rw-r--r--res/values-zh-rHK/strings_group.xml53
-rw-r--r--res/values-zh-rTW/arrays.xml1
-rw-r--r--res/values-zh-rTW/strings.xml3
-rw-r--r--res/values-zh-rTW/strings_group.xml53
-rw-r--r--res/values-zu/arrays.xml1
-rw-r--r--res/values-zu/strings.xml3
-rw-r--r--res/values/arrays.xml108
-rwxr-xr-xres/values/config.xml10
-rw-r--r--res/values/strings.xml138
-rw-r--r--res/values/strings_ba.xml127
-rw-r--r--res/values/strings_group.xml57
-rw-r--r--res/values/styles.xml7
-rw-r--r--res/xml/bcast_source_info_details_fragment.xml96
-rw-r--r--res/xml/bluetooth_broadcast_pin_config.xml65
-rw-r--r--res/xml/bluetooth_device_details_fragment.xml18
-rw-r--r--res/xml/bluetooth_group_details_fragment.xml46
-rw-r--r--res/xml/bluetooth_screen.xml10
-rw-r--r--res/xml/bluetooth_search_bcast_sources.xml35
-rw-r--r--res/xml/connected_devices.xml84
-rw-r--r--res/xml/developer_mobile_network_list.xml40
-rw-r--r--res/xml/development_settings.xml22
-rwxr-xr-x[-rw-r--r--]res/xml/location_settings.xml7
-rwxr-xr-x[-rw-r--r--]res/xml/mobile_network_settings.xml24
-rw-r--r--res/xml/my_device_info.xml18
-rw-r--r--res/xml/other_sound_settings.xml5
-rw-r--r--res/xml/prefer_vonr_list.xml20
-rw-r--r--res/xml/previously_connected_group_devices.xml97
-rw-r--r--res/xml/sound_settings.xml6
-rwxr-xr-xres/xml/uplmn_editor.xml49
-rwxr-xr-xres/xml/uplmn_settings.xml36
-rw-r--r--res/xml/wifi_tether_settings.xml8
-rw-r--r--src/com/android/settings/AirplaneModeEnabler.java19
-rw-r--r--src/com/android/settings/DBReadAsyncTask.java108
-rw-r--r--src/com/android/settings/IccLockSettings.java17
-rw-r--r--src/com/android/settings/ResetNetworkConfirm.java11
-rw-r--r--src/com/android/settings/Settings.java2
-rw-r--r--src/com/android/settings/SettingsActivity.java19
-rw-r--r--src/com/android/settings/SmqSettings.java65
-rw-r--r--src/com/android/settings/TestingSettingsBroadcastReceiver.java2
-rwxr-xr-x[-rw-r--r--]src/com/android/settings/TetherSettings.java26
-rw-r--r--src/com/android/settings/Utils.java62
-rw-r--r--src/com/android/settings/applications/manageapplications/ResetAppsHelper.java2
-rw-r--r--src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java13
-rw-r--r--src/com/android/settings/bluetooth/BADeviceVolumeController.java277
-rw-r--r--src/com/android/settings/bluetooth/BADeviceVolumePreference.java67
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java129
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java90
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDevicePreference.java44
-rw-r--r--src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java29
-rw-r--r--src/com/android/settings/bluetooth/BluetoothEnabler.java6
-rw-r--r--src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java8
-rw-r--r--src/com/android/settings/bluetooth/BluetoothPairingController.java11
-rw-r--r--src/com/android/settings/bluetooth/BluetoothPairingService.java7
-rw-r--r--src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java13
-rw-r--r--src/com/android/settings/bluetooth/DevicePickerFragment.java2
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothDetailsButtonsController.java332
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothDetailsController.java101
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothDeviceUpdater.java96
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothDevicesAvailableMediaController.java134
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothDevicesAvailableMediaDeviceUpdater.java117
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothDevicesBondedController.java129
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothDevicesBondedUpdater.java92
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothDevicesConnectedController.java127
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothDevicesConnectedUpdater.java135
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothFragment.java158
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothGroupDeviceUpdater.java77
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothProfileSwitchConfirmDialog.java129
-rw-r--r--src/com/android/settings/bluetooth/GroupBluetoothSettingsPreference.java166
-rw-r--r--src/com/android/settings/bluetooth/GroupConnectedBluetoothDeviceUpdater.java154
-rw-r--r--src/com/android/settings/bluetooth/GroupForgetDialogFragment.java103
-rw-r--r--src/com/android/settings/bluetooth/GroupSavedBluetoothDeviceUpdater.java143
-rw-r--r--src/com/android/settings/bluetooth/GroupUtils.java669
-rw-r--r--src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java40
-rw-r--r--src/com/android/settings/bluetooth/SavedBluetoothTwsDeviceUpdater.java91
-rw-r--r--src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java69
-rw-r--r--src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java41
-rw-r--r--src/com/android/settings/connecteddevice/GroupConnectedBluetoothDevicesController.java174
-rw-r--r--src/com/android/settings/connecteddevice/GroupPreviouslyConnectedDeviceDashboardFragment.java87
-rw-r--r--src/com/android/settings/connecteddevice/GroupPreviouslyConnectedDevicePreferenceController.java148
-rw-r--r--src/com/android/settings/connecteddevice/GroupSavedDeviceController.java164
-rw-r--r--src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java58
-rw-r--r--src/com/android/settings/connecteddevice/SavedTwsDeviceGroupController.java157
-rw-r--r--src/com/android/settings/connecteddevice/usb/UsbBackend.java5
-rw-r--r--src/com/android/settings/core/TogglePreferenceController.java12
-rw-r--r--src/com/android/settings/core/gateway/SettingsGateway.java4
-rw-r--r--src/com/android/settings/datausage/BillingCyclePreference.java1
-rw-r--r--src/com/android/settings/datausage/CellDataPreference.java23
-rw-r--r--src/com/android/settings/datausage/DataUsageSummary.java15
-rw-r--r--src/com/android/settings/development/BluetoothSnoopLogPreferenceController.java14
-rw-r--r--src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java7
-rw-r--r--src/com/android/settings/development/Prefer5GNetworkListController.java354
-rw-r--r--src/com/android/settings/development/Prefer5GNetworkListFragment.java69
-rw-r--r--src/com/android/settings/development/Prefer5GNetworkSummaryController.java177
-rw-r--r--src/com/android/settings/development/PreferVonrController.java113
-rw-r--r--src/com/android/settings/development/PreferVonrSettings.java256
-rw-r--r--src/com/android/settings/development/SmartDdsSwitchPreferenceController.java242
-rw-r--r--src/com/android/settings/development/WifiCoverageExtendPreferenceController.java79
-rw-r--r--src/com/android/settings/development/bluetooth/AbstractBluetoothDialogPreferenceController.java18
-rw-r--r--src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreference.java10
-rw-r--r--src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java24
-rw-r--r--src/com/android/settings/development/bluetooth/BluetoothHDAudioPreferenceController.java1
-rw-r--r--src/com/android/settings/development/bluetooth/BluetoothQualityDialogPreferenceController.java3
-rw-r--r--src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java8
-rw-r--r--src/com/android/settings/deviceinfo/HardwareInfoPreferenceController.java9
-rw-r--r--src/com/android/settings/deviceinfo/ImsConnector.java106
-rw-r--r--src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java102
-rwxr-xr-xsrc/com/android/settings/deviceinfo/SoftwareVersionPreferenceController.java73
-rwxr-xr-xsrc/com/android/settings/deviceinfo/StorageSizePreferenceController.java93
-rwxr-xr-x[-rw-r--r--]src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java31
-rw-r--r--src/com/android/settings/deviceinfo/WifiMacAddressPreferenceController.java25
-rw-r--r--src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java47
-rw-r--r--src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceController.java12
-rw-r--r--src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java7
-rw-r--r--src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java26
-rw-r--r--src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceController.java119
-rwxr-xr-x[-rw-r--r--]src/com/android/settings/display/BrightnessLevelPreferenceController.java2
-rwxr-xr-xsrc/com/android/settings/location/AgpsPreferenceController.java80
-rw-r--r--src/com/android/settings/location/AppSettingsInjector.java33
-rw-r--r--src/com/android/settings/location/DimmableIZatIconPreference.java227
-rw-r--r--src/com/android/settings/location/LocationSettings.java1
-rw-r--r--src/com/android/settings/network/AirplaneModePreferenceController.java112
-rw-r--r--src/com/android/settings/network/MobileNetworkListController.java6
-rw-r--r--src/com/android/settings/network/MobileNetworkPreferenceController.java59
-rw-r--r--src/com/android/settings/network/NetworkDashboardFragment.java10
-rw-r--r--src/com/android/settings/network/ProviderModelSliceHelper.java2
-rw-r--r--src/com/android/settings/network/SubscriptionUtil.java2
-rw-r--r--src/com/android/settings/network/SubscriptionsChangeListener.java1
-rw-r--r--src/com/android/settings/network/TetherPreferenceController.java29
-rw-r--r--src/com/android/settings/network/UiccSlotUtil.java22
-rw-r--r--src/com/android/settings/network/apn/ApnEditor.java84
-rwxr-xr-xsrc/com/android/settings/network/apn/ApnPreference.java7
-rwxr-xr-xsrc/com/android/settings/network/apn/ApnSettings.java226
-rw-r--r--src/com/android/settings/network/telephony/BackupCallingPreferenceController.java46
-rw-r--r--src/com/android/settings/network/telephony/CellInfoUtil.java135
-rw-r--r--src/com/android/settings/network/telephony/DataDefaultSubscriptionController.java52
-rw-r--r--src/com/android/settings/network/telephony/DataDuringCallsPreferenceController.java19
-rw-r--r--src/com/android/settings/network/telephony/DefaultSubscriptionController.java138
-rwxr-xr-xsrc/com/android/settings/network/telephony/Enabled5GPreferenceController.java341
-rw-r--r--src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java94
-rw-r--r--src/com/android/settings/network/telephony/LegacyIncrementalScanBroadcastReceiver.java220
-rw-r--r--src/com/android/settings/network/telephony/MobileDataPreferenceController.java89
-rw-r--r--src/com/android/settings/network/telephony/MobileDataSlice.java10
-rw-r--r--src/com/android/settings/network/telephony/MobileNetworkSettings.java76
-rw-r--r--src/com/android/settings/network/telephony/MobileNetworkSwitchController.java71
-rw-r--r--src/com/android/settings/network/telephony/NetworkOperatorPreference.java9
-rw-r--r--src/com/android/settings/network/telephony/NetworkScanHelper.java151
-rw-r--r--src/com/android/settings/network/telephony/NetworkSelectSettings.java80
-rwxr-xr-x[-rw-r--r--]src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java115
-rw-r--r--src/com/android/settings/network/telephony/TelephonyUtils.java227
-rw-r--r--src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java2
-rwxr-xr-xsrc/com/android/settings/network/telephony/UserPLMNEditorActivity.java406
-rwxr-xr-xsrc/com/android/settings/network/telephony/UserPLMNListActivity.java748
-rwxr-xr-xsrc/com/android/settings/network/telephony/UserPLMNPreferenceController.java83
-rw-r--r--src/com/android/settings/network/telephony/WifiCallingPreferenceController.java4
-rw-r--r--src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java29
-rw-r--r--src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java30
-rw-r--r--src/com/android/settings/notification/CallConnectedTonePreferenceController.java49
-rw-r--r--src/com/android/settings/notification/SoundSettings.java4
-rw-r--r--src/com/android/settings/password/ChooseLockGeneric.java2
-rw-r--r--src/com/android/settings/security/SimLockPreferenceController.java4
-rw-r--r--src/com/android/settings/widget/GroupOptionsPreference.java414
-rw-r--r--src/com/android/settings/widget/GroupPreferenceCategory.java66
-rw-r--r--src/com/android/settings/wifi/WifiConfigController2.java27
-rwxr-xr-x[-rw-r--r--]src/com/android/settings/wifi/WifiSettings.java27
-rw-r--r--src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java99
-rw-r--r--src/com/android/settings/wifi/dpp/WifiDppUtils.java3
-rw-r--r--src/com/android/settings/wifi/p2p/WifiP2pSettings.java9
-rw-r--r--src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceController.java115
-rw-r--r--src/com/android/settings/wifi/tether/WifiTetherAutoOffPreferenceController.java17
-rw-r--r--src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceController.java137
-rw-r--r--src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java11
-rw-r--r--src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java11
-rw-r--r--src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java54
-rw-r--r--src/com/android/settings/wifi/tether/WifiTetherSettings.java77
-rw-r--r--tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceControllerTest.java36
-rw-r--r--tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java32
-rw-r--r--tests/robotests/src/com/android/settings/wifi/WifiSettingsTest.java2
-rw-r--r--tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java35
-rw-r--r--tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java4
-rw-r--r--tests/unit/src/com/android/settings/network/NetworkProviderCallsSmsFragmentTest.java3
-rw-r--r--tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java7
-rw-r--r--tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java4
-rw-r--r--tests/unit/src/com/android/settings/network/telephony/NetworkScanHelperTest.java2
-rw-r--r--tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java5
-rw-r--r--tests/unit/src/com/android/settings/panel/PanelFeatureProviderImplTest.java1
-rw-r--r--tests/unit/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceControllerTest.java240
364 files changed, 14175 insertions, 800 deletions
diff --git a/Android.bp b/Android.bp
index dce25d7dda..780741654e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -35,6 +35,27 @@ java_library {
],
}
+soong_config_module_type_import {
+ from: "device/qcom/qssi/Android.bp",
+ module_types: [
+ "bredr_vs_btadva_java_defaults",
+ ],
+}
+
+bredr_vs_btadva_java_defaults {
+ name: "btadva_settings_java_defaults",
+
+ soong_config_variables: {
+ bredr_or_btadva: {
+ btadva: {
+ srcs: [
+ ":settings-bluetooth-adva-srcs",
+ ],
+ }
+ }
+ }
+}
+
// Build the Settings APK
android_library {
name: "Settings-core",
@@ -42,6 +63,8 @@ android_library {
defaults: [
"SettingsLibDefaults",
"SettingsLib-search-defaults",
+ "framework-wifi-vendor-hide-access-defaults",
+ "btadva_settings_java_defaults",
],
srcs: ["src/**/*.java"],
@@ -80,6 +103,8 @@ android_library {
"telephony-common",
"ims-common",
"app-compat-annotations",
+ "telephony-ext",
+ "extphonelib",
],
}
@@ -110,6 +135,9 @@ android_app {
optimize: {
proguard_flags_files: ["proguard.flags"],
},
+ libs: [
+ "extphonelib"
+ ],
}
android_library_import {
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c84132fd43..88476002a7 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -109,6 +109,7 @@
<uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION" />
<uses-permission android:name="android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK" />
<uses-permission android:name="android.permission.ALLOW_PLACE_IN_MULTI_PANE_SETTINGS" />
+ <uses-permission android:name="com.qualcomm.qti.permission.USE_EXT_TELEPHONY_SERVICE" />
<application
android:name=".SettingsApplication"
@@ -125,6 +126,7 @@
android:appComponentFactory="androidx.core.app.CoreComponentFactory">
<uses-library android:name="org.apache.http.legacy"/>
+ <uses-library android:name="com.qti.extphone.extphonelib"/>
<uses-library android:name="androidx.window.extensions" android:required="false"/>
<uses-library android:name="androidx.window.sidecar" android:required="false"/>
@@ -221,7 +223,6 @@
<intent-filter android:priority="1">
<action android:name="android.settings.WIRELESS_SETTINGS" />
<action android:name="android.settings.AIRPLANE_MODE_SETTINGS" />
- <action android:name="com.android.settings.sim.SIM_SUB_INFO_SETTINGS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
@@ -1151,6 +1152,37 @@
android:value="true" />
</activity>
+ <!-- Keep compatibility with old shortcuts. -->
+ <activity-alias android:name="DisplaySettings"
+ android:label="@string/display_settings"
+ android:exported="true"
+ android:targetActivity="Settings$DisplaySettingsActivity">
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="com.android.settings.DisplaySettings" />
+ </activity-alias>
+ <activity android:name="Settings$SMQQtiFeedbackActivity"
+ android:exported="true"
+ android:label="@string/qtifeedback_settings_title"
+ android:icon="@drawable/ic_settings_qti_feedback"
+ android:enabled="false"
+ android:taskAffinity="">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ <intent-filter android:priority="250">
+ <action android:name="com.android.settings.action.SETTINGS" />
+ </intent-filter>
+ <meta-data android:name="com.android.settings.category"
+ android:value="com.android.settings.category.ia.system" />
+ <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
+ android:value="@string/qtifeedback_intent_action" />
+ <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"
+ android:value="true" />
+ <meta-data android:name="com.android.settings.summary"
+ android:resource="@string/qtifeedback_settings_subtitle" />
+ </activity>
+
<activity
android:name="Settings$SmartAutoRotateSettingsActivity"
android:label="@string/accelerometer_title"
@@ -4258,6 +4290,24 @@
android:theme="@style/SudThemeGlif.Light">
</activity>
+ <activity android:name=".network.telephony.UserPLMNListActivity"
+ android:exported="true"
+ android:label="@string/uplmn_settings_title"
+ android:configChanges="orientation|screenSize|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".network.telephony.UserPLMNEditorActivity"
+ android:exported="true"
+ android:label="@string/uplmn_settings_title"
+ android:configChanges="orientation|screenSize|keyboardHidden">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
<!-- This is the longest AndroidManifest.xml ever. -->
</application>
</manifest>
diff --git a/NOTICE b/NOTICE
index c5b1efa7aa..acbd108de7 100644
--- a/NOTICE
+++ b/NOTICE
@@ -10,6 +10,54 @@
See the License for the specific language governing permissions and
limitations under the License.
+________________________________________
+
+Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+______________________________________
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved
+ * Not a contribution
+
+ * Copyright (C) 2019 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.
+ */
+______________________________________
Apache License
Version 2.0, January 2004
diff --git a/proguard.flags b/proguard.flags
index 3ed713636b..45294c8fff 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -67,6 +67,11 @@
public <init>(android.content.Context, android.net.Uri);
}
+# Keep ImsConnector members for FeatureConnector.Listener<ImsManager>
+-keep class com.android.settings.deviceinfo.ImsConnector {
+ *;
+}
+
# Keep WM Jetpack classes and callbacks
-keep class androidx.window.** { *; }
-dontwarn androidx.window.extensions.**
diff --git a/res/drawable-mdpi/ic_settings_qti_feedback.png b/res/drawable-mdpi/ic_settings_qti_feedback.png
new file mode 100644
index 0000000000..e7c0dae3c3
--- /dev/null
+++ b/res/drawable-mdpi/ic_settings_qti_feedback.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_settings_qti_feedback.png b/res/drawable-xhdpi/ic_settings_qti_feedback.png
new file mode 100644
index 0000000000..a20f94e91f
--- /dev/null
+++ b/res/drawable-xhdpi/ic_settings_qti_feedback.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_settings_qti_feedback.png b/res/drawable-xxhdpi/ic_settings_qti_feedback.png
new file mode 100644
index 0000000000..5d0ccf6a43
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_settings_qti_feedback.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_settings_qti_feedback.png b/res/drawable-xxxhdpi/ic_settings_qti_feedback.png
new file mode 100644
index 0000000000..3dfb55d6c7
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_settings_qti_feedback.png
Binary files differ
diff --git a/res/drawable/ic_volume_media_bt.xml b/res/drawable/ic_volume_media_bt.xml
new file mode 100644
index 0000000000..de0376040c
--- /dev/null
+++ b/res/drawable/ic_volume_media_bt.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ Not a contribution
+-->
+
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M9 3l0.01 10.55c-0.6-0.34-1.28-0.55-2-0.55C4.79 13 3 14.79 3 17s1.79 4 4.01 4S11 19.21 11 17V7h4V3H9zm12 9.43L17.57 9h-0.6v4.55l-2.75-2.75-0.85 0.85 L16.73 15l-3.35 3.35 0.85 0.85 2.75-2.75V21h0.6L21 17.57 18.42 15 21 12.43zm-2.83-1.13l1.13 1.13-1.13 1.13V11.3zm1.13 6.27l-1.13 1.13v-2.26l1.13 1.13z" />
+</vector>
diff --git a/res/layout/bluetooth_audio_codec_dialog.xml b/res/layout/bluetooth_audio_codec_dialog.xml
index 9636427055..1fd9de8021 100644
--- a/res/layout/bluetooth_audio_codec_dialog.xml
+++ b/res/layout/bluetooth_audio_codec_dialog.xml
@@ -52,8 +52,16 @@
layout="@layout/preference_widget_dialog_radiobutton"/>
<include
+ android:id="@+id/bluetooth_audio_codec_aptx_adaptive"
+ layout="@layout/preference_widget_dialog_radiobutton"/>
+
+ <include
android:id="@+id/bluetooth_audio_codec_ldac"
layout="@layout/preference_widget_dialog_radiobutton"/>
+
+ <include
+ android:id="@+id/bluetooth_audio_codec_aptx_twsp"
+ layout="@layout/preference_widget_dialog_radiobutton"/>
</RadioGroup>
<include
diff --git a/res/layout/bluetooth_group_options.xml b/res/layout/bluetooth_group_options.xml
new file mode 100644
index 0000000000..d518f057ba
--- /dev/null
+++ b/res/layout/bluetooth_group_options.xml
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView
+ android:id="@+id/id_tv_groupid"
+ style="@style/SettingsLibActionButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+
+ <TextView
+ android:text="@string/active"
+ android:id="@+id/id_tv_status"
+ style="@style/SettingsLibActionButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+
+ <ProgressBar
+ android:id="@+id/id_progress_group_scan"
+ style="?android:attr/progressBarStyleSmallTitle"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_alignParentRight="true"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="16dip"
+ android:layout_weight="1"
+ android:minWidth="32dp"
+ android:text="@string/refresh_group" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/id_btn_connect"
+ style="@style/GroupOptionsButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/connect_group" />
+
+ <Button
+ android:id="@+id/id_btn_disconnect"
+ style="@style/GroupOptionsButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/disconnect_group" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/id_btn_forget"
+ style="@style/GroupOptionsButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="forget" />
+
+ <Button
+ android:id="@+id/id_btn_refresh"
+ style="@style/GroupOptionsButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/refresh_group" />
+
+ <Button
+ android:id="@+id/id_btn_refresh_cancel"
+ style="@style/GroupOptionsButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/cancel_refresh_group" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/id_btn_group_add_source"
+ style="@style/GroupOptionsButton"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:text="@string/add_source_group" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/preference_ba_device_volume_slider.xml b/res/layout/preference_ba_device_volume_slider.xml
new file mode 100644
index 0000000000..a7806c1083
--- /dev/null
+++ b/res/layout/preference_ba_device_volume_slider.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ Not a contribution
+-->
+
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:gravity="center_vertical"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:clickable="false"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:id="@+id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="44dp"
+ android:gravity="start|center_vertical"
+ android:orientation="horizontal"
+ android:paddingEnd="12dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp">
+ <com.android.internal.widget.PreferenceImageView
+ android:id="@android:id/icon"
+ android:layout_width="24dp"
+ android:layout_height="24dp"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="8dp">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:paddingStart="12dp"
+ android:singleLine="true"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
+ android:textColor="?android:attr/textColorPrimary"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"/>
+ <!-- Preference should place its actual preference widget here. -->
+ <LinearLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:gravity="end|center_vertical"
+ android:paddingStart="12dp"
+ android:orientation="vertical"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <SeekBar
+ android:id="@*android:id/seekbar"
+ android:layout_gravity="center_vertical"
+ android:paddingStart="12dp"
+ android:layout_width="match_parent"
+ android:layout_height="48dp"/>
+
+ <TextView
+ android:id="@+id/suppression_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="12dp"
+ android:layout_gravity="center_vertical|start"
+ android:textAlignment="viewStart"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:visibility="gone"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
+ android:textColor="?android:attr/textColorSecondary"/>
+
+ </LinearLayout>
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/select_source_prompt.xml b/res/layout/select_source_prompt.xml
new file mode 100644
index 0000000000..50cf2faa36
--- /dev/null
+++ b/res/layout/select_source_prompt.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+android:orientation="vertical"
+android:paddingStart="16dip"
+android:layout_marginTop="@dimen/bluetooth_dialog_padding_top"
+android:layout_width="match_parent"
+android:layout_height="match_parent">
+
+<EditText
+ android:id="@+id/broadcastPINcode"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/bluetooth_dialog_padding"
+ android:layout_marginLeft="@dimen/bluetooth_dialog_padding"
+ android:layout_marginStart="@dimen/bluetooth_dialog_padding"
+ android:layout_marginEnd="@dimen/bluetooth_dialog_padding"
+ android:gravity="center_vertical"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
+ android:ems="16"
+ android:hint="Broadcast PIN"
+ android:inputType="text" />
+
+</LinearLayout>
diff --git a/res/layout/wifi_dialog.xml b/res/layout/wifi_dialog.xml
index 6f83e5cd1e..5472de2333 100644
--- a/res/layout/wifi_dialog.xml
+++ b/res/layout/wifi_dialog.xml
@@ -399,6 +399,13 @@
android:visibility="gone"/>
</LinearLayout>
+ <CheckBox android:id="@+id/share_this_wifi"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/wifi_item_content"
+ android:textSize="14sp"
+ android:text="@string/share_this_wifi" />
+
<LinearLayout android:id="@+id/metered_settings_fields"
android:layout_width="match_parent"
android:layout_height="wrap_content"
diff --git a/res/values-af/arrays.xml b/res/values-af/arrays.xml
index 879a0f0e23..cdadf99415 100644
--- a/res/values-af/arrays.xml
+++ b/res/values-af/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Interne toestelberging"</item>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 6a85581aae..5c0d35b847 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Geen klank of vibrasie nie"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Geen klank of vibrasie nie en verskyn laer in gespreksafdeling"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Kan lui of vibreer op grond van fooninstellings"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Wys prioriteitkennisgewings hieronder. Altyd stil."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Wys prioriteitkennisgewings hieronder. Altyd stil."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Wys prioriteitkennisgewings hieronder. Altyd stil."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Wys kennisgewings as \'n banier boaan die skerm wanneer die toestel ontsluit is"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Alle \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"-kennisgewings"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Alle <xliff:g id="APP_NAME">%1$s</xliff:g>-kennisgewings"</string>
diff --git a/res/values-am/arrays.xml b/res/values-am/arrays.xml
index 794942b2ab..c3320ec5c4 100644
--- a/res/values-am/arrays.xml
+++ b/res/values-am/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"የውስጥ መሣሪያ ማከማቻ"</item>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 0156dfe69a..f383792d79 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"ምንም ድምጽ ወይም ንዝረት የለም"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"ምንም ድምጽ ወይም ንዝረት የለም እና በውይይት ክፍል ላይ አይታይም"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"በእርስዎ የስልክ ቅንብሮች የሚወሰን ሆኖ ሊደውል ወይም ሊነዝር ይችላል"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"ከዚህ በታች ቅድሚያ የሚሰጣቸው ማሳወቂያዎችን ያሳያል። ሁልጊዜ ጸጥ ያለ።"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"ከዚህ በታች ቅድሚያ የሚሰጣቸው ማሳወቂያዎችን ያሳያል። ሁልጊዜ ጸጥ ያለ።"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"ከዚህ በታች ቅድሚያ የሚሰጣቸው ማሳወቂያዎችን ያሳያል። ሁልጊዜ ጸጥ ያለ።"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"መሣሪያ ሲከፈት፣ ማሳወቂያዎችን እንደ ሰንደቅ በማያ ገጹ አናት ላይ እንዳለ አሳይ"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"ሁሉም «<xliff:g id="APP_NAME">%1$s</xliff:g>» ማሳወቂያዎች"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"ሁሉም የ<xliff:g id="APP_NAME">%1$s</xliff:g> ማሳወቂያዎች"</string>
diff --git a/res/values-ar/arrays.xml b/res/values-ar/arrays.xml
index 2f19c460de..debb3c1f89 100644
--- a/res/values-ar/arrays.xml
+++ b/res/values-ar/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"مساحة تخزين الجهاز الداخلية"</item>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 4b271e437e..e7d3c86a38 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -4097,6 +4097,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"بدون صوت أو اهتزاز وتظهر في موضع أسفل في قسم المحادثات"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"يمكن إصدار رنين أو اهتزاز بناءً على إعدادات الهاتف."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"عند فتح قفل الجهاز، تظهر الإشعارات في صورة بانر أعلى الشاشة."</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"يتم عرض هذه الإشعارات أسفل الإشعارات ذات الأولوية. كتم الصوت دائمًا."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"يتم عرض هذه الإشعارات أسفل الإشعارات ذات الأولوية. كتم الصوت دائمًا."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"يتم عرض هذه الإشعارات أسفل الإشعارات ذات الأولوية. كتم الصوت دائمًا."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"جميع إشعارات \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"جميع إشعارات \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="default_notification_assistant" msgid="243718059890346442">"الإشعارات التكيّفية"</string>
diff --git a/res/values-az/arrays.xml b/res/values-az/arrays.xml
index 08a2243083..dc41d16021 100644
--- a/res/values-az/arrays.xml
+++ b/res/values-az/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Cihazın daxili yaddaşı"</item>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index fd75a8769b..09af767b1b 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Səs və ya vibrasiya yoxdur"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Söhbət siyahısının aşağısında səssiz və vibrasiyasız görünür"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Telefon ayarlarına əsasən zəng çala və ya titrəyə bilər"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Mühüm bildirişlərin aşağısında göstərilir. Həmişə səssiz."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Mühüm bildirişlərin aşağısında göstərilir. Həmişə səssiz."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Mühüm bildirişlərin aşağısında göstərilir. Həmişə səssiz."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Kilidi açılmış cihazda bütün bildirişlər ekranın yuxarısındakı banner şəklində göstərilsin"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Bütün \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" bildirişləri"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Bütün <xliff:g id="APP_NAME">%1$s</xliff:g> bildirişləri"</string>
diff --git a/res/values-b+sr+Latn/arrays.xml b/res/values-b+sr+Latn/arrays.xml
index 3c3be0f2e5..598abbb248 100644
--- a/res/values-b+sr+Latn/arrays.xml
+++ b/res/values-b+sr+Latn/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Skladište unutrašnjeg uređaja"</item>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 3d3b671d7b..99e9696e1f 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -3958,6 +3958,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Bez zvuka i vibriranja"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Bez zvuka i vibriranja i prikazuje se u nastavku odeljka za konverzacije"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Može da zvoni ili vibrira u zavisnosti od podešavanja telefona"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Prikazuje se ispod prioritetnih obaveštenja. Uvek nečujno."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Prikazuje se ispod prioritetnih obaveštenja. Uvek nečujno."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Prikazuje se ispod prioritetnih obaveštenja. Uvek nečujno."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Kada je uređaj otključan, prikazuje obaveštenja kao baner u vrhu ekrana"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Sva obaveštenja aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Sva obaveštenja aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-be/arrays.xml b/res/values-be/arrays.xml
index bb99c97cb2..099a9d009c 100644
--- a/res/values-be/arrays.xml
+++ b/res/values-be/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Унутраная памяць прылады"</item>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index fc1d429a7c..ca07432412 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -4006,6 +4006,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Без гуку ці вібрацыі"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Паказваецца без гуку ці вібрацыі ў раздзеле размоў"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"У залежнасці ад налад тэлефона магчымы званок або вібрацыя"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Паказвае ўнізе апавяшчэнні з высокім прыярытэтам. Заўсёды без гуку."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Паказвае ўнізе апавяшчэнні з высокім прыярытэтам. Заўсёды без гуку."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Паказвае ўнізе апавяшчэнні з высокім прыярытэтам. Заўсёды без гуку."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Калі прылада разблакіравана, паказваць апавяшчэнні ў выглядзе банера ўверсе экрана"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Усе апавяшчэнні праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Усе апавяшчэнні праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
diff --git a/res/values-bg/arrays.xml b/res/values-bg/arrays.xml
index bcb64eba42..4591642067 100644
--- a/res/values-bg/arrays.xml
+++ b/res/values-bg/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Вътрешно хранилище на устройство"</item>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index b2625836ce..edbbc8d8fa 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -3914,6 +3914,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Без звук или вибриране"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Без звук или вибриране и се показва по-долу в секцията с разговори"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Може да звъни или да вибрира въз основа на настройките за телефона"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Показва се под приоритетните известия. Винаги в тих режим."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Показва се под приоритетните известия. Винаги в тих режим."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Показва се под приоритетните известия. Винаги в тих режим."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Когато устройството е отключено, известията се показват като банер в горната част на екрана"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Всички известия от: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Всички известия от: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
@@ -4813,6 +4816,8 @@
<item quantity="other"><xliff:g id="NUMBER">%s</xliff:g> секунди</item>
<item quantity="one">1 секунда</item>
</plurals>
+ <string name="qtifeedback_settings_title"> Обратна връзка за хардуер</string>
+ <string name="qtifeedback_settings_subtitle">Qualcomm Technologies, Inc доклади</string>
<string name="automatic_storage_manager_settings" msgid="519158151463974656">"Управление на хранилището"</string>
<string name="automatic_storage_manager_text" msgid="6900593059927987273">"За да ви помогне да освободите място за съхранение, мениджърът на хранилището премахва от устройството ви резервните копия на снимки и видеоклипове."</string>
<string name="automatic_storage_manager_days_title" msgid="5077286114860539367">"Премахване на снимките и видеоклиповете"</string>
diff --git a/res/values-bn/arrays.xml b/res/values-bn/arrays.xml
index 03504a4d27..385cf262c4 100644
--- a/res/values-bn/arrays.xml
+++ b/res/values-bn/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"ইন্টারনাল ডিভাইসের স্টোরেজ"</item>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index e38a3d6c58..f36ca9170e 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"আওয়াজ করবে না বা ভাইব্রেট হবে না"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"আওয়াজ করবে না বা ভাইব্রেট হবে না এবং কথোপকথন বিভাগের নিচের দিকে দেখা যাবে"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"ফোনের সেটিংস অনুযায়ী ফোন রিং বা ভাইব্রেট হতে পারে"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"অগ্রাধিকারযুক্ত বিজ্ঞপ্তির নিচে দেখানো হয়। সবসময় সাইলেন্ট।"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"অগ্রাধিকারযুক্ত বিজ্ঞপ্তির নিচে দেখানো হয়। সবসময় সাইলেন্ট।"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"অগ্রাধিকারযুক্ত বিজ্ঞপ্তির নিচে দেখানো হয়। সবসময় সাইলেন্ট।"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"কোনও ডিভাইস আনলক করা হলে বিজ্ঞপ্তি, স্ক্রিনের উপরে একটি ব্যানার হিসেবে দেখানো হয়"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"সমস্ত \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" বিজ্ঞপ্তি"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"সমস্ত <xliff:g id="APP_NAME">%1$s</xliff:g> সংক্রান্ত বিজ্ঞপ্তি"</string>
diff --git a/res/values-bs/arrays.xml b/res/values-bs/arrays.xml
index 218bed2552..0de1a52c46 100644
--- a/res/values-bs/arrays.xml
+++ b/res/values-bs/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Unutrašnja pohrana uređaja"</item>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 3240bb2827..41d5cf5ddd 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -3960,6 +3960,9 @@
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Može zvoniti ili vibrirati na osnovu postavki vašeg telefona"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Kada je uređaj otključan, vidite obavještenja u vidu banera na vrhu ekrana"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Sva obavještenja aplikacije \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Prikazuje se ispod prioritetnih obavještenja. Uvijek nečujno."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Prikazuje se ispod prioritetnih obavještenja. Uvijek nečujno."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Prikazuje se ispod prioritetnih obavještenja. Uvijek nečujno."</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Sva obavještenja aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Prilagodljiva obavještenja"</string>
<plurals name="notifications_sent_daily" formatted="false" msgid="1479283620504341566">
diff --git a/res/values-ca/arrays.xml b/res/values-ca/arrays.xml
index 209a52245a..aa5d2043a1 100644
--- a/res/values-ca/arrays.xml
+++ b/res/values-ca/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Emmagatzematge intern del dispositiu"</item>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 6067808459..bc222a2ecb 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Sense so ni vibració"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Sense so ni vibració i es mostra més avall a la secció de converses"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Pot sonar o vibrar en funció de la configuració del telèfon"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Es mostra a sota de les notificacions prioritàries. Sempre silenciosa."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Es mostra a sota de les notificacions prioritàries. Sempre silenciosa."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Es mostra a sota de les notificacions prioritàries. Sempre silenciosa."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Quan el dispositiu estigui desbloquejat, mostra les notificacions en forma de bàner a la part superior de la pantalla"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Totes les notificacions de: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Totes les notificacions de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-cs/arrays.xml b/res/values-cs/arrays.xml
index 7b191af988..b01a7ec8f1 100644
--- a/res/values-cs/arrays.xml
+++ b/res/values-cs/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Interní úložiště zařízení"</item>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 11b93e42df..bfadd874d7 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -4004,6 +4004,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Žádný zvuk ani vibrace"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Žádný zvuk ani vibrace a zobrazuje se níže v sekci konverzací"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Vyzvání nebo vibruje podle nastavení telefonu"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Zobrazí oznámení s nižší prioritou. Vždy tichý režim."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Zobrazí oznámení s nižší prioritou. Vždy tichý režim."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Zobrazí oznámení s nižší prioritou. Vždy tichý režim."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Když je zařízení odemčené, zobrazovat oznámení jako banner v horní části obrazovky"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"<xliff:g id="APP_NAME">%1$s</xliff:g>: všechna oznámení"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Všechna oznámení aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-da/arrays.xml b/res/values-da/arrays.xml
index 103f57d79d..2562fcf944 100644
--- a/res/values-da/arrays.xml
+++ b/res/values-da/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Intern lagerplads på enheden"</item>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 9466c0657d..3dbf489ccd 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Ingen lyd eller vibration"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Ingen lyd eller vibration, og den vises længere nede i samtalesektionen"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Kan ringe eller vibrere baseret på telefonens indstillinger"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Viser notifikationer med lav prioritet. Altid lydløs."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Viser notifikationer med lav prioritet. Altid lydløs."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Viser notifikationer med lav prioritet. Altid lydløs."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Når enheden er låst op, vises notifikationer som et banner øverst på skærmen"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Alle notifikationer fra \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Alle notifikationer for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-de/arrays.xml b/res/values-de/arrays.xml
index 2e869b7e4b..6ea46aff16 100644
--- a/res/values-de/arrays.xml
+++ b/res/values-de/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Interner Gerätespeicher"</item>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 8a4be36a99..12aa65639b 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -3915,6 +3915,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Kein Ton und keine Vibration"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Kein Ton und keine Vibration, erscheint weiter unten im Bereich „Unterhaltungen“"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Kann klingeln oder vibrieren, abhängig von den Telefoneinstellungen"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Erscheinen unter den wichtigen Benachrichtigungen. Immer lautlos."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Erscheinen unter den wichtigen Benachrichtigungen. Immer lautlos."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Erscheinen unter den wichtigen Benachrichtigungen. Immer lautlos."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Bei entsperrtem Gerät Benachrichtigungen als Banner oben auf dem Bildschirm anzeigen"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Alle Benachrichtigungen von „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Alle Benachrichtigungen von <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-el/arrays.xml b/res/values-el/arrays.xml
index 725d8c2c0c..82d04f015f 100644
--- a/res/values-el/arrays.xml
+++ b/res/values-el/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Εσωτερικός αποθηκευτικός χώρος της συσκευής"</item>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 7ac8306356..61d89272b0 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Χωρίς ήχο ή δόνηση"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Χωρίς ήχο ή δόνηση και εμφανίζεται χαμηλά στην ενότητα συζητήσεων"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Ενδέχεται να κουδουνίζει ή να δονείται βάσει των ρυθμίσεων του τηλεφώνου"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Εμφανίζεται κάτω από ειδοποιήσεις προτεραιότητας. Πάντα σε σίγαση."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Εμφανίζεται κάτω από ειδοποιήσεις προτεραιότητας. Πάντα σε σίγαση."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Εμφανίζεται κάτω από ειδοποιήσεις προτεραιότητας. Πάντα σε σίγαση."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Όταν η συσκευή είναι ξεκλειδωμένη, οι ειδοποιήσεις εμφανίζονται ως banner επάνω στην οθόνη"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Όλες οι ειδοποιήσεις \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Όλες οι ειδοποιήσεις <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-en-rAU/arrays.xml b/res/values-en-rAU/arrays.xml
index d4852dd899..c2626fbdd3 100644
--- a/res/values-en-rAU/arrays.xml
+++ b/res/values-en-rAU/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Internal device storage"</item>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 912a557ebf..dce20bae07 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"No sound or vibration and appears lower in conversation section"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"May ring or vibrate based on phone settings"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Displays below priority notifications. Always silent."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Displays below priority notifications. Always silent."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Displays below priority notifications. Always silent."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"When device is unlocked, show notifications as a banner across the top of the screen"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"All \'<xliff:g id="APP_NAME">%1$s</xliff:g>\' notifications"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"All <xliff:g id="APP_NAME">%1$s</xliff:g> notifications"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 15b1f31853..894a78e805 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"No sound or vibration and appears lower in conversation section"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"May ring or vibrate based on phone settings"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Displays below priority notifications. Always silent."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Displays below priority notifications. Always silent."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Displays below priority notifications. Always silent."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"When device is unlocked, show notifications as a banner across the top of the screen"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"All \'<xliff:g id="APP_NAME">%1$s</xliff:g>\' notifications"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"All <xliff:g id="APP_NAME">%1$s</xliff:g> notifications"</string>
diff --git a/res/values-en-rGB/arrays.xml b/res/values-en-rGB/arrays.xml
index d4852dd899..c2626fbdd3 100644
--- a/res/values-en-rGB/arrays.xml
+++ b/res/values-en-rGB/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Internal device storage"</item>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 19840a7a25..e047c9f943 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"No sound or vibration and appears lower in conversation section"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"May ring or vibrate based on phone settings"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Displays below priority notifications. Always silent."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Displays below priority notifications. Always silent."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Displays below priority notifications. Always silent."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"When device is unlocked, show notifications as a banner across the top of the screen"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"All \'<xliff:g id="APP_NAME">%1$s</xliff:g>\' notifications"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"All <xliff:g id="APP_NAME">%1$s</xliff:g> notifications"</string>
diff --git a/res/values-en-rIN/arrays.xml b/res/values-en-rIN/arrays.xml
index d4852dd899..c2626fbdd3 100644
--- a/res/values-en-rIN/arrays.xml
+++ b/res/values-en-rIN/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Internal device storage"</item>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 0adec02837..709aa82b55 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"No sound or vibration"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"No sound or vibration and appears lower in conversation section"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"May ring or vibrate based on phone settings"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Displays below priority notifications. Always silent."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Displays below priority notifications. Always silent."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Displays below priority notifications. Always silent."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"When device is unlocked, show notifications as a banner across the top of the screen"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"All \'<xliff:g id="APP_NAME">%1$s</xliff:g>\' notifications"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"All <xliff:g id="APP_NAME">%1$s</xliff:g> notifications"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index c812f7f1ca..de5abfae83 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‎‎‎‎‎‎No sound or vibration‎‏‎‎‏‎"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‏‎‎No sound or vibration and appears lower in conversation section‎‏‎‎‏‎"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‏‎‎‏‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎‎May ring or vibrate based on phone settings‎‏‎‎‏‎"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‏‎‏‏‏‎‏‎‎‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‏‎‏‎‏‏‏‎Displays below priority notifications. Always silent.‎‏‎‎‏‎"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‎‏‏‎‎‎‎‏‎‏‎‏‏‏‎‏‏‎‎‎‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‎‏‎‏‏‎Displays below priority notifications. Always silent.‎‏‎‎‏‎"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‏‏‎‎‏‏‏‎‎Displays below priority notifications. Always silent.‎‏‎‎‏‎"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‎‎‏‎‎‏‎‏‎‏‎When device is unlocked, show notifications as a banner across the top of the screen‎‏‎‎‏‎"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‏‏‏‎‏‎‏‎‏‏‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‎All \"‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎\" notifications‎‏‎‎‏‎"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‎‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎All ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ notifications‎‏‎‎‏‎"</string>
diff --git a/res/values-es-rUS/arrays.xml b/res/values-es-rUS/arrays.xml
index 74bb789b54..ffb9f67066 100644
--- a/res/values-es-rUS/arrays.xml
+++ b/res/values-es-rUS/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Dispositivo de almacenamiento interno"</item>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 92fbdd5fa6..f8f2a213c5 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -3915,6 +3915,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"No suena ni vibra, y aparece en la parte inferior de la sección de conversaciones."</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Puede sonar o vibrar en función de la configuración del teléfono."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Con el dispositivo desbloqueado, mostrar notificaciones como banner en la parte superior de la pantalla"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Se muestra debajo de las notificaciones de prioridad. Siempre en silencio."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Se muestra debajo de las notificaciones de prioridad. Siempre en silencio."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Se muestra debajo de las notificaciones de prioridad. Siempre en silencio."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Todas las notificaciones de \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Todas las notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Notificaciones adaptables"</string>
diff --git a/res/values-es/arrays.xml b/res/values-es/arrays.xml
index 9996c21642..08f1e03a20 100644
--- a/res/values-es/arrays.xml
+++ b/res/values-es/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Almacenamiento de dispositivo interno"</item>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index b3d9c2b27a..c8e020582a 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Sin sonido ni vibración, y se muestra más abajo en la sección de conversaciones"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Puede sonar o vibrar según los ajustes del teléfono"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Cuando el dispositivo esté desbloqueado, muestra las notificaciones en la parte superior"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Muestra las notificaciones con prioridad baja. Siempre en silencio."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Muestra las notificaciones con prioridad baja. Siempre en silencio."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Muestra las notificaciones con prioridad baja. Siempre en silencio."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Todas las notificaciones de \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Todas las notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Notificaciones adaptativas"</string>
@@ -4812,6 +4815,8 @@
<item quantity="one">1 segundo</item>
</plurals>
<string name="automatic_storage_manager_settings" msgid="519158151463974656">"Gestionar almacenamiento"</string>
+ <string name="qtifeedback_settings_title">Comentarios sobre el hardware</string>
+ <string name="qtifeedback_settings_subtitle">Informes de Qualcomm Technologies, Inc</string>
<string name="automatic_storage_manager_text" msgid="6900593059927987273">"Para liberar espacio, el Administrador de Almacenamiento borrará de tu dispositivo las fotos y vídeos que tengan copia de seguridad."</string>
<string name="automatic_storage_manager_days_title" msgid="5077286114860539367">"Borrar fotos y vídeos"</string>
<string name="automatic_storage_manager_preference_title" msgid="3483357910142595444">"Administrador de almacenamiento"</string>
diff --git a/res/values-et/arrays.xml b/res/values-et/arrays.xml
index bcdb33d2fd..d331a232ae 100644
--- a/res/values-et/arrays.xml
+++ b/res/values-et/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Seadme sisemine salvestusruum"</item>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 2265879140..0867d60169 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -3914,6 +3914,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Ilma heli ja vibreerimiseta"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Ilma heli ja vibreerimiseta, kuvatakse vestluste jaotises allpool"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Võib telefoni seadete põhjal heliseda või vibreerida"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Kuvatakse prioriteetsete märguannete all. Alati vaikne."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Kuvatakse prioriteetsete märguannete all. Alati vaikne."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Kuvatakse prioriteetsete märguannete all. Alati vaikne."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Kui seade on avatud, kuvatakse märguanded bännerina ekraanikuva ülaosas"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Kõik tüüpi „<xliff:g id="APP_NAME">%1$s</xliff:g>” märguanded"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Kõik rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> märguanded"</string>
diff --git a/res/values-eu/arrays.xml b/res/values-eu/arrays.xml
index a95a0a1d47..7bc6dd4c0b 100644
--- a/res/values-eu/arrays.xml
+++ b/res/values-eu/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Gailuaren barneko memoria"</item>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 8a97c4b09d..e15783c482 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Ez du tonurik jotzen edo dar-dar egiten"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Ez du tonurik jotzen edo dar-dar egiten, eta elkarrizketaren atalaren behealdean agertzen da"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Tonua jo edo dar-dar egin dezake, telefonoaren ezarpenen arabera"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Lehentasunik ez duten jakinarazpenak erakusten ditu. Beti isilik."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Lehentasunik ez duten jakinarazpenak erakusten ditu. Beti isilik."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Lehentasunik ez duten jakinarazpenak erakusten ditu. Beti isilik."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Gailua desblokeatuta dagoenean, erakutsi jakinarazpenak banda gisa pantailaren goialdean"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" aplikazioaren jakinarazpen guztiak"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren jakinarazpen guztiak"</string>
diff --git a/res/values-fa/arrays.xml b/res/values-fa/arrays.xml
index b8b0b0d2c6..58c4f79293 100644
--- a/res/values-fa/arrays.xml
+++ b/res/values-fa/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"دستگاه ذخیره‌سازی داخلی"</item>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 5d5e979561..71bbe3d780 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"بدون صدا یا لرزش"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"بدون صدا و لرزش در پایین بخش مکالمه نشان داده می‌شود"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"بسته به تنظیمات ممکن است تلفن زنگ بزند یا لرزش داشته باشد"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"اعلان‌های با اولویت پایین را نشان می‌دهد. همیشه بی‌صدا."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"اعلان‌های با اولویت پایین را نشان می‌دهد. همیشه بی‌صدا."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"اعلان‌های با اولویت پایین را نشان می‌دهد. همیشه بی‌صدا."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"وقتی قفل دستگاه باز می‌شود، اعلان‌ها به‌صورت برنمایی در بالای صفحه‌نمایش نشان داده شود"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"همه اعلان‌های «<xliff:g id="APP_NAME">%1$s</xliff:g>»"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"همه اعلان‌های <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-fi/arrays.xml b/res/values-fi/arrays.xml
index 4c39095276..e7703d3dc9 100644
--- a/res/values-fi/arrays.xml
+++ b/res/values-fi/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Laitteen sisäinen tallennustila"</item>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 6fc37f54ab..627aeec08f 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Ei ääntä tai värinää ja näkyy alempana keskusteluosiossa"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Voi soida tai väristä puhelimen asetuksista riippuen"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Kun laitteen lukitus on avattuna, näytä ilmoitukset bannerina sivun yläreunassa"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Näytetään priorisoitujen ilmoitusten alapuolella. Aina äänetön."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Näytetään priorisoitujen ilmoitusten alapuolella. Aina äänetön."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Näytetään priorisoitujen ilmoitusten alapuolella. Aina äänetön."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Kaikki ilmoitukset: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Kaikki ilmoitukset: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Mukautuvat ilmoitukset"</string>
diff --git a/res/values-fr-rCA/arrays.xml b/res/values-fr-rCA/arrays.xml
index ab61755974..f846cd56f6 100644
--- a/res/values-fr-rCA/arrays.xml
+++ b/res/values-fr-rCA/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Mémoire interne du mobile"</item>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 86a2cec2e8..7e37cbce9e 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Aucun son ni vibration, et s\'affiche plus bas dans la section des conversations"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Peut sonner ou vibrer, selon les paramètres du téléphone"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Lorsque l\'appareil est déverrouillé, afficher les notifications dans une bannière dans le haut de l\'écran"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"S\'affiche sous les notifications prioritaires. Toujours silencieux."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"S\'affiche sous les notifications prioritaires. Toujours silencieux."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"S\'affiche sous les notifications prioritaires. Toujours silencieux."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Toutes les notifications de « <xliff:g id="APP_NAME">%1$s</xliff:g> »"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Toutes les notifications de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Notifications adaptatives"</string>
diff --git a/res/values-fr/arrays.xml b/res/values-fr/arrays.xml
index 32ce72e7d8..b8d6364503 100644
--- a/res/values-fr/arrays.xml
+++ b/res/values-fr/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Mémoire interne du mobile"</item>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 70456155e0..d3b9495098 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Ni son, ni vibreur"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Ni son, ni vibreur ; affichage plus bas dans la section \"Conversations\""</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Son ou vibreur, selon les paramètres du téléphone"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"S\'affiche sous les notifications prioritaires. Toujours silencieux."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"S\'affiche sous les notifications prioritaires. Toujours silencieux."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"S\'affiche sous les notifications prioritaires. Toujours silencieux."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Lorsque l\'appareil est déverrouillé, afficher les notifications dans une bannière en haut de l\'écran"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Toutes les notifications de \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Toutes les notifications de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-fr/strings_group.xml b/res/values-fr/strings_group.xml
new file mode 100644
index 0000000000..6e4cdf3f3b
--- /dev/null
+++ b/res/values-fr/strings_group.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="group_id">"identifiant de groupe"</string>
+ <string name="refresh_group">"Rafraîchir le groupe"</string>
+ <string name="cancel_refresh_group">"Annuler l'actualisation"</string>
+ <string name="disconnect_group">"Déconnecter le groupe"</string>
+ <string name="connect_group">"Connecter le groupe"</string>
+ <string name="forget_group">"Groupe Oublier"</string>
+ <string name="group_previously_connected_screen_title">"Groupe précédemment connecté"</string>
+ <string name="connected_group">"Groupe connecté"</string>
+ <string name="group_connected_device_media_device_title">"Appareils multimédia de groupe"</string>
+ <string name="group_settings">"Groupe"</string>
+ <string name="previous_connected_see_all_groups">"Groupe précédemment connecté"</string>
+ <string name="group_options">"Options de groupe"</string>
+ <string name="group_connected_devices">"Des appareils connectés"</string>
+ <string name="group_active_devices">"Appareils actifs"</string>
+ <string name="group_bonded_devices">"Dispositif lié"</string>
+ <string name="active">"Active"</string>
+ <string name="groupaudio_unpair_dialog_title">"Oubliez le groupe?"</string>
+ <string name="groupaudio_unpair_dialog_body">"Votre téléphone ne sera plus associé à l'ensemble"<xliff:g id="setid">%1$s</xliff:g></string>
+ <string name="groupaudio_unpair_dialog_forget_confirm_button">"Groupe Oublier"</string>
+ <string name="group_apply_changes_dialog_title">Appliquer les modifications à tous les membres du groupe ?</string>
+ <string name="group_confirm_dialog_body">Mêmes changements applicables à tous les membres du groupe <xliff:g id="groupid">%1$s</xliff:g></string>
+ <string name="group_confirm_dialog_apply_button">Appliquer</string>
+</resources>
diff --git a/res/values-gl/arrays.xml b/res/values-gl/arrays.xml
index 2ae1b1ef07..83f1bc6dd8 100644
--- a/res/values-gl/arrays.xml
+++ b/res/values-gl/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Almacenamento interno do dispositivo"</item>
diff --git a/res/values-gu/arrays.xml b/res/values-gu/arrays.xml
index 75e2e7f69b..d1994a34d3 100644
--- a/res/values-gu/arrays.xml
+++ b/res/values-gu/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"આંતરિક ડિવાઇસ સ્ટોરેજ"</item>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index b8b5633bb5..a8087ba1fc 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"કોઈપણ સાઉન્ડ અથવા વાઇબ્રેશન નથી"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"કોઈપણ સાઉન્ડ અથવા વાઇબ્રેશન નથી અને વાતચીત વિભાગમાં તે વધુ નીચેની દિશાએ દેખાય છે"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"ફોન સેટિંગના આધારે રિંગ અથવા વાઇબ્રેટ થઈ શકે છે"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"પ્રાધાન્યતાવાળા નોટિફિકેશન નીચે બતાવે છે. હંમેશાં સાઇલન્ટ."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"પ્રાધાન્યતાવાળા નોટિફિકેશન નીચે બતાવે છે. હંમેશાં સાઇલન્ટ."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"પ્રાધાન્યતાવાળા નોટિફિકેશન નીચે બતાવે છે. હંમેશાં સાઇલન્ટ."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"ડિવાઇસ અનલૉક થયેલું હોય ત્યારે, સ્ક્રીનના ઉપરના ભાગ પર બૅનરના સ્વરૂપમાં નોટિફિકેશન બતાવો"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"ના તમામ નોટિફિકેશન"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"<xliff:g id="APP_NAME">%1$s</xliff:g>ના બધા નોટિફિકેશન"</string>
diff --git a/res/values-hi/arrays.xml b/res/values-hi/arrays.xml
index e4e1ad52e0..f1dad8974b 100644
--- a/res/values-hi/arrays.xml
+++ b/res/values-hi/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"आंतरिक डिवाइस मेमोरी"</item>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index d017a6e0b5..fddbfee31e 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"किसी तरह की आवाज़ या वाइब्रेशन न हो"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"इससे किसी तरह की आवाज़ या वाइब्रेशन नहीं होता और \'बातचीत\', सेक्शन में सबसे नीचे दिखती है"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"फ़ोन की सेटिंग के आधार पर, सूचना आने पर घंटी बज सकती है या वाइब्रेशन हो सकता है"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"कम ज़रूरी सूचनाएं दिखती हैं. दिखते समय आवाज़ और वाइब्रेशन हमेशा बंद रहते हैं."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"कम ज़रूरी सूचनाएं दिखती हैं. दिखते समय आवाज़ और वाइब्रेशन हमेशा बंद रहते हैं."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"कम ज़रूरी सूचनाएं दिखती हैं. दिखते समय आवाज़ और वाइब्रेशन हमेशा बंद रहते हैं."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"जब डिवाइस अनलॉक हो, तो स्क्रीन के सबसे ऊपर बैनर के रूप में सूचनाएं दिखाएं"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" की सभी सूचनाएं"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"<xliff:g id="APP_NAME">%1$s</xliff:g> की सभी सूचनाएं"</string>
diff --git a/res/values-hr/arrays.xml b/res/values-hr/arrays.xml
index 79325775d2..467c180e19 100644
--- a/res/values-hr/arrays.xml
+++ b/res/values-hr/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Interno pohranjivanje na uređaj"</item>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 8f4fdad10f..1e3966af61 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -3960,6 +3960,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Bez zvuka ili vibracije"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Bez zvuka ili vibracije i prikazuje se pri dnu odjeljka razgovora"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Možda će zvoniti ili vibrirati, ovisno o postavkama telefona"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Prikazuje obavijesti nižeg prioriteta. Uvijek bešumno."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Prikazuje obavijesti nižeg prioriteta. Uvijek bešumno."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Prikazuje obavijesti nižeg prioriteta. Uvijek bešumno."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Kad je uređaj otključan, prikaži obavijesti kao natpis pri vrhu zaslona"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Sve obavijesti aplikacije \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Sve obavijesti aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-hu/arrays.xml b/res/values-hu/arrays.xml
index 13ab2f40fb..2b21e7bb54 100644
--- a/res/values-hu/arrays.xml
+++ b/res/values-hu/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Belső tárhely"</item>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 2894335437..856c595eea 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Nincs hang és rezgés"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Nincs hang és rezgés, továbbá lejjebb jelenik meg a beszélgetések szakaszában"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"A telefonbeállítások alapján csöröghet és rezeghet"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Az elsőbbségi értesítések alatt jelenik meg. Mindig némítva van."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Az elsőbbségi értesítések alatt jelenik meg. Mindig némítva van."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Az elsőbbségi értesítések alatt jelenik meg. Mindig némítva van."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Feloldott állapotban az értesítések megjelenítése szalag formájában a képernyő felső részén"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"A(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” összes értesítése"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Az összes <xliff:g id="APP_NAME">%1$s</xliff:g>-értesítés"</string>
diff --git a/res/values-hy/arrays.xml b/res/values-hy/arrays.xml
index d84bb54e63..981a899174 100644
--- a/res/values-hy/arrays.xml
+++ b/res/values-hy/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Սարքի ներքին պահոց"</item>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 9371bba522..bb1ef4fd6f 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Հայտնվում է զրույցների ցանկի ներքևում, առանց ձայնի և թրթռոցի"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Կարող է զնգալ կամ թրթռալ (հեռախոսի կարգավորումներից կախված)"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Երբ սարքն ապակողպված է, ծանուցումները ցույց տալ էկրանի վերևի ազդերիզի տեսքով"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Ցուցադրվում են կարևոր ծանուցումների տակ: Միշտ անձայն:"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Ցուցադրվում են կարևոր ծանուցումների տակ: Միշտ անձայն:"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Ցուցադրվում են կարևոր ծանուցումների տակ: Միշտ անձայն:"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"«<xliff:g id="APP_NAME">%1$s</xliff:g>» պիտակով բոլոր ծանուցումները"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի բոլոր ծանուցումները"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Հարմարվող ծանուցումներ"</string>
diff --git a/res/values-in/arrays.xml b/res/values-in/arrays.xml
index f1c9c1067b..ca39167713 100644
--- a/res/values-in/arrays.xml
+++ b/res/values-in/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Penyimpanan perangkat internal"</item>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index c0c2566022..568dcd3f0b 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Tidak ada suara atau getaran dan ditampilkan lebih rendah di bagian percakapan"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Dapat berdering atau bergetar berdasarkan setelan ponsel"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Saat perangkat tidak terkunci, notifikasi ditampilkan sebagai banner di bagian atas layar"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Ditampilkan di bawah notifikasi prioritas. Selalu senyap."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Ditampilkan di bawah notifikasi prioritas. Selalu senyap."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Ditampilkan di bawah notifikasi prioritas. Selalu senyap."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Semua notifikasi \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Semua notifikasi <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Notifikasi Adaptif"</string>
diff --git a/res/values-is/arrays.xml b/res/values-is/arrays.xml
index 89e2f1827b..b24f342e1d 100644
--- a/res/values-is/arrays.xml
+++ b/res/values-is/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Innbyggð geymsla tækis"</item>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index d3e5eef711..d664e314e4 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Ekkert hljóð eða titringur"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Ekkert hljóð eða titringur og birtist neðar í samtalshluta"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Gæti hringt eða titrað eftir stillingum símans"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Birtir tilkynningar með lítinn forgang. Alltaf án hljóðs."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Birtir tilkynningar með lítinn forgang. Alltaf án hljóðs."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Birtir tilkynningar með lítinn forgang. Alltaf án hljóðs."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Birta tilkynningar á borða efst á skjánum þegar tækið er opið"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Allar tilkynningar frá „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Allar tilkynningar frá <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-it/arrays.xml b/res/values-it/arrays.xml
index 287eec6a58..5d944a361b 100644
--- a/res/values-it/arrays.xml
+++ b/res/values-it/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Memorizzazione su dispositivo interno"</item>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index e408720954..0c4d900689 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Nessun suono o vibrazione"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Nessun suono o vibrazione e appare più in basso nella sezione delle conversazioni"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Può suonare o vibrare in base alle impostazioni del telefono"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Vengono mostrate le notifiche con priorità bassa. Sempre silenziose."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Vengono mostrate le notifiche con priorità bassa. Sempre silenziose."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Vengono mostrate le notifiche con priorità bassa. Sempre silenziose."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Quando il dispositivo è sbloccato, mostra le notifiche come banner in cima allo schermo"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Tutte le notifiche di \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Tutte le notifiche di <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-iw/arrays.xml b/res/values-iw/arrays.xml
index 89efdcc6a7..4c9ee84961 100644
--- a/res/values-iw/arrays.xml
+++ b/res/values-iw/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"אחסון פנימי במכשיר"</item>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 8e62ae00dc..6f77433098 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -4006,6 +4006,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"ללא צליל או רטט"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"ללא צליל או רטט ומופיעה למטה בקטע התראות השיחה"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"ייתכן שיופעל צלצול או רטט בהתאם להגדרות הטלפון"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"מציגה התראות בעדיפות נמוכה. תמיד שקטה."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"מציגה התראות בעדיפות נמוכה. תמיד שקטה."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"מציגה התראות בעדיפות נמוכה. תמיד שקטה."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"כשהמכשיר לא נעול, התראות יוצגו כבאנר בראש המסך"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"כל ההתראות של​ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"כל ההתראות של <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-ja/arrays.xml b/res/values-ja/arrays.xml
index 5120065ce0..14a5c52409 100644
--- a/res/values-ja/arrays.xml
+++ b/res/values-ja/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"内部デバイスストレージ"</item>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 9c67fd1402..caf7ad2482 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"着信音もバイブレーションも無効になります"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"着信音もバイブレーションも無効になり会話セクションの下に表示されます"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"スマートフォンの設定を基に着信音またはバイブレーションが有効になります"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"優先度の低い通知を表示します。常に通知音は鳴りません。"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"優先度の低い通知を表示します。常に通知音は鳴りません。"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"優先度の低い通知を表示します。常に通知音は鳴りません。"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"デバイスのロックが解除されているとき、画面上部にバナーとして通知を表示します"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」のすべての通知"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"<xliff:g id="APP_NAME">%1$s</xliff:g> のすべての通知"</string>
diff --git a/res/values-ja/strings_group.xml b/res/values-ja/strings_group.xml
new file mode 100644
index 0000000000..e6a9b9d37b
--- /dev/null
+++ b/res/values-ja/strings_group.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="group_id">グループID</string>
+ <string name="refresh_group">グループの更新</string>
+ <string name="cancel_refresh_group">更新をキャンセル</string>
+ <string name="disconnect_group">グループを切断します</string>
+ <string name="connect_group">グループを接続する</string>
+ <string name="forget_group">グループを忘れる</string>
+ <string name="group_previously_connected_screen_title">以前に接続したグループ</string>
+ <string name="group_settings">グループ</string>
+ <string name="previously_connected_group_screen_title">以前に接続したグループ</string>
+ <string name="previous_connected_see_all_groups">すべてのグループを見る</string>
+ <string name="group_options">グループオプション</string>
+ <string name="group_connected_devices">接続されたデバイス</string>
+ <string name="group_active_devices">アクティブデバイス </string>
+ <string name="group_bonded_devices">結合デバイス</string>
+ <string name="active">アクティブ</string>
+ <string name="groupaudio_unpair_dialog_title">グループを忘れますか?</string>
+ <string name="groupaudio_unpair_dialog_body">お使いの携帯電話は セットとペアリングされなくなりました <xliff:g id="setid">%1$s</xliff:g></string>
+ <string name="groupaudio_unpair_dialog_forget_confirm_button">グループを忘れる</string>
+ <string name="group_apply_changes_dialog_title">すべてのグループメンバーに変更を適用する ? </string>
+ <string name="group_confirm_dialog_body">グループのすべてのメンバーに同じ変更が適用されます <xliff:g id="groupid">%1$s</xliff:g></string>
+ <string name="group_confirm_dialog_apply_button">適用する</string>
+</resources>
diff --git a/res/values-ka/arrays.xml b/res/values-ka/arrays.xml
index 2f983afff3..86f7bb0f19 100644
--- a/res/values-ka/arrays.xml
+++ b/res/values-ka/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"შიდა მოწყობილობის მეხსიერება"</item>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index d11c6d0bd6..da1b8b2742 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"ხმისა და ვიბრაციის გარეშე"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"ხმისა და ვიბრაციის გარეშე, ჩნდება მიმოწერების სექციის ქვედა ნაწილში"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"დარეკვა ან ვიბრაცია ტელეფონის პარამეტრების მიხედვით"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"აჩვენებს ნაკლებად პრიორიტეტულ შეტყობინებებს. ყოველთვის ჩუმია."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"აჩვენებს ნაკლებად პრიორიტეტულ შეტყობინებებს. ყოველთვის ჩუმია."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"აჩვენებს ნაკლებად პრიორიტეტულ შეტყობინებებს. ყოველთვის ჩუმია."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"როცა მოწყობილობა განბლოკილია, შეტყობინებები გამოჩნდეს ეკრანის ზედა ნაწილზე გადაჭიმული ბანერის სახით"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“-ის ყველა შეტყობინება"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის ყველა შეტყობინება"</string>
diff --git a/res/values-kk/arrays.xml b/res/values-kk/arrays.xml
index 8097032a51..8d81018296 100644
--- a/res/values-kk/arrays.xml
+++ b/res/values-kk/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Ішкі құрылғы жады"</item>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 932a83b286..fc37706ab4 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -3910,8 +3910,11 @@
<string name="convo_not_supported_summary" msgid="4285471045268268048">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы әңгіме функцияларының көбісін қолдамайды. Әңгімені маңызды деп орната алмайсыз және олар қалқыма хабарлар түрінде шықпайды."</string>
<string name="notification_channel_summary_min" msgid="8823399508450176842">"Ашылмалы мәзірде хабарландыруларды бір жолға жию"</string>
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Дыбыс не діріл болмайды."</string>
- <string name="notification_conversation_summary_low" msgid="6352818857388412326">"Дыбыс не діріл болмайды, әңгімелер бөлімінің төмен жағында тұрады."</string>
- <string name="notification_channel_summary_default" msgid="3674057458265438896">"Телефон параметрлеріне байланысты дыбыстық сигнал не діріл болуы мүмкін."</string>
+ <string name="notification_conversation_summary_low" msgid="6352818857388412326">"Дыбыс не діріл болмайды, әңгімелер бөлімінің төмен жағында тұрады."</string>
+ <string name="notification_channel_summary_default" msgid="3674057458265438896">"Телефон параметрлеріне байланысты дыбыстық сигнал не діріл болуы мүмкін."</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Маңыздылығы төмен хабарландыруларды көрсетеді. Үнемі дыбыссыз режимде болады."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Маңыздылығы төмен хабарландыруларды көрсетеді. Үнемі дыбыссыз режимде болады."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Маңыздылығы төмен хабарландыруларды көрсетеді. Үнемі дыбыссыз режимде болады."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Құрылғының құлпы ашылғанда, хабарландырулар экранның жоғарғы жағында баннер ретінде көрсетіледі."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Барлық \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" хабарландырулары"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Барлық <xliff:g id="APP_NAME">%1$s</xliff:g> хабарландырулары"</string>
diff --git a/res/values-km/arrays.xml b/res/values-km/arrays.xml
index 0dbb161c61..2671845bff 100644
--- a/res/values-km/arrays.xml
+++ b/res/values-km/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"ឧបករណ៍​ផ្ទុក​ខាង​ក្នុង"</item>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 58de8ab99f..8e49f456fa 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -3915,6 +3915,9 @@
<string name="notification_channel_summary_high" msgid="3411637309360617621">"បង្ហាញការ​ជូនដំណឹងជា​ផ្ទាំងបដានៅផ្នែក​ខាងលើ​អេក្រង់ នៅពេល​ឧបករណ៍មិនជាប់សោ"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"ការជូនដំណឹង​ទាំងអស់ពី \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"ការជូនដំណឹង​ទាំងអស់ពី <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"បង្ហាញ​ខាងក្រោម​ការជូនដំណឹង​អាទិភាព។ បិទសំឡេង​ជានិច្ច។"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"បង្ហាញ​ខាងក្រោម​ការជូនដំណឹង​អាទិភាព។ បិទសំឡេង​ជានិច្ច។"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"បង្ហាញ​ខាងក្រោម​ការជូនដំណឹង​អាទិភាព។ បិទសំឡេង​ជានិច្ច។"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"ការជូនដំណឹង​ដែល​មានភាព​បត់បែន"</string>
<plurals name="notifications_sent_daily" formatted="false" msgid="1479283620504341566">
<item quantity="other">ការជូន​ដំណឹង ~<xliff:g id="NUMBER_1">%d</xliff:g> ក្នុងមួយថ្ងៃ</item>
diff --git a/res/values-kn/arrays.xml b/res/values-kn/arrays.xml
index 31c4b4d25a..3c69c609fa 100644
--- a/res/values-kn/arrays.xml
+++ b/res/values-kn/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"ಆಂತರಿಕ ಸಾಧನ ಸಂಗ್ರಹಣೆ"</item>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 6ce6d1ad1a..875d173a0e 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"ಯಾವುದೇ ಧ್ವನಿ ಅಥವಾ ವೈಬ್ರೇಷನ್‌ ಆಗುವುದಿಲ್ಲ, ಸಂಭಾಷಣೆ ವಿಭಾಗದ ಕೆಳಭಾಗದಲ್ಲಿ ಗೋಚರಿಸುತ್ತದೆ"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಆಧರಿಸಿ ಫೋನ್ ರಿಂಗ್ ಅಥವಾ ವೈಬ್ರೇಟ್ ಆಗುತ್ತದೆ"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"ಸಾಧನವನ್ನು ಅನ್‌ಲಾಕ್ ಮಾಡಿದಾಗ, ಅಧಿಸೂಚನೆಗಳನ್ನು ಪರದೆಯ ಮೇಲ್ಭಾಗದಲ್ಲಿ ಬ್ಯಾನರ್‌ ಆಗಿ ತೋರಿಸಿ"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"ಆದ್ಯತೆಯ ಅಧಿಸೂಚನೆಗಳ ಅಡಿಯಲ್ಲಿ ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತದೆ. ಯಾವಾಗಲೂ ನಿಶ್ಶಬ್ದ."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"ಆದ್ಯತೆಯ ಅಧಿಸೂಚನೆಗಳ ಅಡಿಯಲ್ಲಿ ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತದೆ. ಯಾವಾಗಲೂ ನಿಶ್ಶಬ್ದ."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"ಆದ್ಯತೆಯ ಅಧಿಸೂಚನೆಗಳ ಅಡಿಯಲ್ಲಿ ಪ್ರದರ್ಶಿಸಲಾಗುತ್ತದೆ. ಯಾವಾಗಲೂ ನಿಶ್ಶಬ್ದ."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"ಎಲ್ಲಾ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ಅಧಿಸೂಚನೆಗಳು"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"ಎಲ್ಲಾ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅಧಿಸೂಚನೆಗಳು"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"ಅಡಾಪ್ಟಿವ್ ಅಧಿಸೂಚನೆಗಳು"</string>
diff --git a/res/values-ko/arrays.xml b/res/values-ko/arrays.xml
index af1b069e6f..d823054d91 100644
--- a/res/values-ko/arrays.xml
+++ b/res/values-ko/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"내부 기기 저장용량"</item>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index cf9e5126e5..dce1b2c198 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -3915,6 +3915,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"소리나 진동이 울리지 않으며 대화 섹션 하단에 표시됨"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"휴대전화 설정에 따라 벨소리나 진동이 울릴 수 있음"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"기기가 잠금 해제되어 있을 때 화면 상단에 알림 배너 표시"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"우선순위 알림 아래에 표시됩니다. 항상 음소거됩니다."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"우선순위 알림 아래에 표시됩니다. 항상 음소거됩니다."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"우선순위 알림 아래에 표시됩니다. 항상 음소거됩니다."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"모든 ‘<xliff:g id="APP_NAME">%1$s</xliff:g>’ 알림"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"모든 <xliff:g id="APP_NAME">%1$s</xliff:g> 알림"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"적응형 알림"</string>
diff --git a/res/values-ko/strings_group.xml b/res/values-ko/strings_group.xml
new file mode 100644
index 0000000000..ceb4022f30
--- /dev/null
+++ b/res/values-ko/strings_group.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="group_id">그룹 ID</string>
+ <string name="refresh_group">그룹 새로 고침</string>
+ <string name="cancel_refresh_group">새로 고침 취소</string>
+ <string name="disconnect_group">그룹 연결 해제</string>
+ <string name="connect_group">연결 그룹</string>
+ <string name="forget_group">그룹 잊어 버려</string>
+ <string name="group_previously_connected_screen_title">이전에 연결된 그룹</string>
+ <string name="group_settings">그룹</string>
+ <string name="previously_connected_group_screen_title">이전에 연결된 그룹</string>
+ <string name="previous_connected_see_all_groups">모든 그룹보기</string>
+ <string name="group_options">그룹 옵션</string>
+ <string name="group_connected_devices">연결된 장치</string>
+ <string name="group_active_devices">활성 장치</string>
+ <string name="group_bonded_devices">보세 장치</string>
+ <string name="active">유효한</string>
+ <string name="groupaudio_unpair_dialog_title">그룹을 잊으셨습니까?</string>
+ <string name="groupaudio_unpair_dialog_body">휴대 전화가 더 이상 세트와 페어링되지 않습니다.
+ <xliff:g id="setid">%1$s</xliff:g></string>
+ <string name="groupaudio_unpair_dialog_forget_confirm_button">그룹 잊어 버려</string>
+ <string name="group_apply_changes_dialog_title">모든 그룹 구성원에게 변경 사항 적용 ? </string>
+ <string name="group_confirm_dialog_body">그룹의 모든 구성원에게 적용되는 동일한 변경 사항 <xliff:g id="groupid">%1$s</xliff:g></string>
+ <string name="group_confirm_dialog_apply_button">대다</string>
+</resources>
diff --git a/res/values-ky/arrays.xml b/res/values-ky/arrays.xml
index cb59e7ae4a..1143a041da 100644
--- a/res/values-ky/arrays.xml
+++ b/res/values-ky/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Ички түзмөк эстутуму"</item>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index c0c8c1ae07..a93df77941 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Үнү чыкпайт же дирилдебейт жана сүйлөшүүлөр тизмесинин ылдый жагында көрүнөт"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Телефондун жөндөөлөрүнө жараша шыңгырап же дирилдеши мүмкүн"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Телефон кулпуланып турганда, билдирмелер экрандын жогору жагында баннер түрүндө көрүнөт"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Маанилүү билдирмелердин ылдый жагында чагылдырылат. Ар дайым үнсүз."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Маанилүү билдирмелердин ылдый жагында чагылдырылат. Ар дайым үнсүз."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Маанилүү билдирмелердин ылдый жагында чагылдырылат. Ар дайым үнсүз."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" колдонмосундагы бардык билдирмелер"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунун бардык билдирмелери"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Ыңгайлаштырылуучу билдирмелер"</string>
diff --git a/res/values-lo/arrays.xml b/res/values-lo/arrays.xml
index b03d165571..a68c08e3fa 100644
--- a/res/values-lo/arrays.xml
+++ b/res/values-lo/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"ພື້ນທີ່ຈັດເກັບຂໍ້ມູນພາຍໃນອຸປະກອນ"</item>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 49e05bb3d0..505eb5621c 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"ບໍ່ມີສຽງ ຫຼື ການສັ່ນເຕືອນ"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"ບໍ່ມີສຽງ ຫຼື ການສັ່ນເຕືອນ ແລະ ປາກົດຢູ່ທາງລຸ່ມຂອງພາກສ່ວນການສົນທະນາ"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"ອາດສົ່ງສຽງ ຫຼື ສັ່ນເຕືອນໂດຍອ້າງອີງຈາກການຕັ້ງຄ່າໂທລະສັບ"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"ສະແດງການແຈ້ງເຕືອນທີ່ຄວາມສຳຄັນຕ່ຳລົງ. ປິດສຽງຕະຫຼອດ."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"ສະແດງການແຈ້ງເຕືອນທີ່ຄວາມສຳຄັນຕ່ຳລົງ. ປິດສຽງຕະຫຼອດ."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"ສະແດງການແຈ້ງເຕືອນທີ່ຄວາມສຳຄັນຕ່ຳລົງ. ປິດສຽງຕະຫຼອດ."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"ເມື່ອປົດລັອກອຸປະກອນແລ້ວ, ໃຫ້ສະແດງການແຈ້ງເຕືອນເປັນປ້າຍຢູ່ເທິງສຸດຂອງໜ້າຈໍ"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"ການແຈ້ງເຕືອນ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ທັງໝົດ"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"ການແຈ້ງເຕືອນ <xliff:g id="APP_NAME">%1$s</xliff:g> ທັງໝົດ"</string>
diff --git a/res/values-lt/arrays.xml b/res/values-lt/arrays.xml
index b9a00e74a2..f16681c9fb 100644
--- a/res/values-lt/arrays.xml
+++ b/res/values-lt/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Vidinė įrenginio saugykla"</item>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index c5fdb2be61..cbc1d6e722 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -4004,6 +4004,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Neskamba ir nevibruoja"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Neskamba, nevibruoja ir rodoma apatinėje pokalbių skilties dalyje"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Gali skambėti arba vibruoti, atsižvelgiant į telefono nustatymus"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Pateikiami po prioritetiniais pranešimais. Visada nutildyti."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Pateikiami po prioritetiniais pranešimais. Visada nutildyti."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Pateikiami po prioritetiniais pranešimais. Visada nutildyti."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Kai įrenginys atrakintas, pranešimai rodomi kaip reklamjuostė ekrano viršuje"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Visi „<xliff:g id="APP_NAME">%1$s</xliff:g>“ pranešimai"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Visi „<xliff:g id="APP_NAME">%1$s</xliff:g>“ pranešimai"</string>
diff --git a/res/values-lv/arrays.xml b/res/values-lv/arrays.xml
index 8e2c787b43..00bd82a89f 100644
--- a/res/values-lv/arrays.xml
+++ b/res/values-lv/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Iekšējā ierīces krātuve"</item>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index f7482399ca..bc0fce7355 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -3958,6 +3958,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Nav skaņas signāla vai vibrācijas"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Nav skaņas signāla vai vibrācijas, kā arī atrodas tālāk sarunu sadaļā"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Atkarībā no tālruņa iestatījumiem var zvanīt vai vibrēt"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Tiek rādīts zem prioritārajiem paziņojumiem. Vienmēr bez skaņas."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Tiek rādīts zem prioritārajiem paziņojumiem. Vienmēr bez skaņas."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Tiek rādīts zem prioritārajiem paziņojumiem. Vienmēr bez skaņas."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Rādīt paziņojumus reklāmkarogā ekrāna augšdaļā, ja ierīce ir atbloķēta"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Visi lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> paziņojumi"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Visi lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> paziņojumi"</string>
diff --git a/res/values-mk/arrays.xml b/res/values-mk/arrays.xml
index f116f62153..062ea864af 100644
--- a/res/values-mk/arrays.xml
+++ b/res/values-mk/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Внатрешен капацитет"</item>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 1d360964ab..00d89a75de 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -3914,7 +3914,10 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Без звук или вибрации"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Без звук или вибрации и се појавува под делот со разговори"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Може да ѕвони или вибрира во зависност од поставките на телефонот"</string>
- <string name="notification_channel_summary_high" msgid="3411637309360617621">"Кога уредот е отклучен, прикажувај ги известувањата како банер на горниот дел од екранот"</string>
+ <string name="notification_channel_summary_high" msgid="3411637309360617621">"Кога уредот е отклучен, прикажувај ги известувањата како банер на горниот дел од екранот"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Се прикажува под приоритетните известувања. Секогаш безгласно."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Се прикажува под приоритетните известувања. Секогаш безгласно."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Се прикажува под приоритетните известувања. Секогаш безгласно."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Сите известувања од „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Сите известувања од <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Адаптивни известувања"</string>
diff --git a/res/values-ml/arrays.xml b/res/values-ml/arrays.xml
index dafc6e2d81..f087d2fc81 100644
--- a/res/values-ml/arrays.xml
+++ b/res/values-ml/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"ആന്തരിക ഉപകരണ സ്റ്റോറേജ്"</item>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 24e6c53ce9..b2e1c1f0a7 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"ശബ്ദമോ വൈബ്രേഷനോ ഇല്ല"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"ശബ്‌ദമോ വൈബ്രേഷനോ ഇല്ല, സംഭാഷണ വിഭാഗത്തിന് താഴെയായി ദൃശ്യമാകും"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"ഫോൺ ക്രമീകരണം അടിസ്ഥാനമാക്കി റിംഗ്/വൈബ്രേറ്റ് ചെയ്യും"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"കുറഞ്ഞ പ്രാധാന്യമുള്ള മുൻഗണനാ അറിയിപ്പുകൾ പ്രദർശിപ്പിക്കുന്നു. എപ്പോഴും നിശബ്‌ദം."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"കുറഞ്ഞ പ്രാധാന്യമുള്ള മുൻഗണനാ അറിയിപ്പുകൾ പ്രദർശിപ്പിക്കുന്നു. എപ്പോഴും നിശബ്‌ദം."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"കുറഞ്ഞ പ്രാധാന്യമുള്ള മുൻഗണനാ അറിയിപ്പുകൾ പ്രദർശിപ്പിക്കുന്നു. എപ്പോഴും നിശബ്‌ദം."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"ഉപകരണം അൺലോക്ക് ചെയ്‌തിരിക്കുമ്പോൾ അറിയിപ്പുകളെ സ്ക്രീനിന്റെ മുകളിൽ ഒരു ബാനറായി കാണിക്കുക"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"എല്ലാ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" അറിയിപ്പുകളും"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"എല്ലാ <xliff:g id="APP_NAME">%1$s</xliff:g> അറിയിപ്പുകളും"</string>
diff --git a/res/values-mn/arrays.xml b/res/values-mn/arrays.xml
index 832563be2f..c410d33213 100644
--- a/res/values-mn/arrays.xml
+++ b/res/values-mn/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Дотоод төхөөрөмжийн сан"</item>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 4c122807b7..bc57db43c9 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Дуу эсвэл чичиргээ байхгүй"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Дуу эсвэл чичиргээ байхгүй бөгөөд харилцан ярианы хэсгийн доод талд харагдана"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Утасны тохиргоонд тулгуурлан хонх дуугаргах эсвэл чичирхийлж болзошгүй"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Доорх ач холбогдолтой мэдэгдлийг харуулдаг. Үргэлж дуугүй байна."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Доорх ач холбогдолтой мэдэгдлийг харуулдаг. Үргэлж дуугүй байна."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Доорх ач холбогдолтой мэдэгдлийг харуулдаг. Үргэлж дуугүй байна."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Төхөөрөмжийн түгжээг тайлсан үед мэдэгдлүүдийг дэлгэцийн дээд хэсэгт баннер болгож харуулах"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\"-н бүх мэдэгдэл"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н бүх мэдэгдэл"</string>
diff --git a/res/values-mr/arrays.xml b/res/values-mr/arrays.xml
index f0e2d930d1..647287fb00 100644
--- a/res/values-mr/arrays.xml
+++ b/res/values-mr/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"अंतर्गत डिव्हाइस स्टोरेज"</item>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index bcb32c4742..8aad353963 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"आवाज किंवा व्हायब्रेशन नाही"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"आवाज किंवा व्हायब्रेशन नाही आणि संभाषण विभागात सर्वात तळाशी दिसते"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"फोन सेटिंग्जच्या आधारावर रिंग किंवा व्हायब्रेट होऊ शकतो"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"कमी प्राधान्य असलेल्या सूचना दाखवते. नेहमी सायलंट."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"कमी प्राधान्य असलेल्या सूचना दाखवते. नेहमी सायलंट."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"कमी प्राधान्य असलेल्या सूचना दाखवते. नेहमी सायलंट."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"डिव्हाइस अनलॉक असताना, स्क्रीनच्या सर्वात वरती बॅनर म्हणून सूचना दाखवा"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"सर्व \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" सूचना"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"सर्व <xliff:g id="APP_NAME">%1$s</xliff:g> वरील सूचना"</string>
diff --git a/res/values-ms/arrays.xml b/res/values-ms/arrays.xml
index 274e55ccbf..c79ba3ee19 100644
--- a/res/values-ms/arrays.xml
+++ b/res/values-ms/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Storan dalaman peranti"</item>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 1ecc106133..d7215b6700 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Tiada bunyi atau getaran dan muncul di sebelah bawah dalam bahagian perbualan"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Mungkin berbunyi atau bergetar berdasarkan tetapan telefon"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Apabila kunci peranti dibuka, tunjukkan pemberitahuan sebagai sepanduk di bahagian atas skrin"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Dipaparkan di bawah pemberitahuan keutamaan. Sentiasa senyap."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Dipaparkan di bawah pemberitahuan keutamaan. Sentiasa senyap."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Dipaparkan di bawah pemberitahuan keutamaan. Sentiasa senyap."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Semua pemberitahuan \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Semua pemberitahuan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Pemberitahuan Boleh Suai"</string>
diff --git a/res/values-my/arrays.xml b/res/values-my/arrays.xml
index 5f8baa19d2..b4682372eb 100644
--- a/res/values-my/arrays.xml
+++ b/res/values-my/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"စက်တွင်းသိုလှောင်ကိရိယာ"</item>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index f5b4ded6b7..69f73b9142 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"အသံ သို့မဟုတ် တုန်ခါမှုမရှိပါ"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"အသံ သို့မဟုတ် တုန်ခါမှုမရှိပါ၊ စကားဝိုင်းကဏ္ဍ၏ အောက်ပိုင်းတွင် မြင်ရသည်"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"ဖုန်းဆက်တင်များပေါ် အခြေခံပြီး အသံမြည်နိုင်သည် သို့မဟုတ် တုန်ခါနိုင်သည်"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"ဦးစားပေးအကြောင်းကြားချက်များ၏ အောက်တွင်ဖော်ပြသည်။ အမြဲအသံတိတ်ရန်။"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"ဦးစားပေးအကြောင်းကြားချက်များ၏ အောက်တွင်ဖော်ပြသည်။ အမြဲအသံတိတ်ရန်။"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"ဦးစားပေးအကြောင်းကြားချက်များ၏ အောက်တွင်ဖော်ပြသည်။ အမြဲအသံတိတ်ရန်။"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"စက်ကို လော့ခ်ဖွင့်ထားပါက အကြောင်းကြားချက်များကို မျက်နှာပြင်၏ထိပ်တွင် နဖူးစည်းအဖြစ် ပြသပါ"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" အကြောင်းကြားချက်အားလုံး"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"<xliff:g id="APP_NAME">%1$s</xliff:g> အကြောင်းကြားချက် အားလုံး"</string>
diff --git a/res/values-nb/arrays.xml b/res/values-nb/arrays.xml
index c212dbbb34..3ad1faac0b 100644
--- a/res/values-nb/arrays.xml
+++ b/res/values-nb/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Intern lagringsenhet"</item>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 870e5189ab..30dd0c8ee2 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Ingen lyd eller vibrering"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Ingen lyd eller vibrering, og vises lavere i samtaledelen"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Kan ringe eller vibrere basert på telefoninnstillingene"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Vises under prioritetsvarsler. Alltid lydløs."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Vises under prioritetsvarsler. Alltid lydløs."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Vises under prioritetsvarsler. Alltid lydløs."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Når enheten låses opp, vises varsler som et banner over toppen av skjermen"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"«<xliff:g id="APP_NAME">%1$s</xliff:g>»: alle varsler"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"<xliff:g id="APP_NAME">%1$s</xliff:g>: alle varsler"</string>
diff --git a/res/values-ne/arrays.xml b/res/values-ne/arrays.xml
index 0c4c653f89..6ed3adaeaa 100644
--- a/res/values-ne/arrays.xml
+++ b/res/values-ne/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"आन्तरिक उपकरण भण्डारण"</item>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 4845b0f6d0..b7529fde15 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"बज्दैन पनि, भाइब्रेट पनि हुँदैन र वार्तालाप खण्डको तलतिर देखा पर्छ"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"फोनको सेटिङका आधारमा घन्टी बज्न वा भाइब्रेट हुन सक्छ"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"डिभाइस अनलक गरिएका बेला सूचना देखाउँदा स्क्रिनको सिरानमा ब्यानरका रूपमा देखाइयोस्"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"न्यून प्राथमिकताका सूचनाहरू देखाउँछ। सधैँ मौन।"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"न्यून प्राथमिकताका सूचनाहरू देखाउँछ। सधैँ मौन।"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"न्यून प्राथमिकताका सूचनाहरू देखाउँछ। सधैँ मौन।"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" का सबै सूचनाहरू"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"<xliff:g id="APP_NAME">%1$s</xliff:g> सम्बन्धी सबै सूचनाहरू"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"अनुकूल पार्न मिल्ने सूचनाहरू"</string>
diff --git a/res/values-nl/arrays.xml b/res/values-nl/arrays.xml
index 875e5bcacd..914c5d9bc6 100644
--- a/res/values-nl/arrays.xml
+++ b/res/values-nl/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Interne apparaatopslag"</item>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index f8934eb48a..bf34fef04e 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Geen geluid of trilling en wordt lager in het gedeelte met gesprekken getoond"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Kan overgaan of trillen op basis van de telefooninstellingen"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Toon meldingen als banner bovenaan het scherm wanneer het apparaat is ontgrendeld"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Wordt weergegeven onder de prioriteitsmeldingen. Altijd stil."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Wordt weergegeven onder de prioriteitsmeldingen. Altijd stil."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Wordt weergegeven onder de prioriteitsmeldingen. Altijd stil."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Alle meldingen van <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Alle meldingen van <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Aanpasbare meldingen"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 15edf892ee..df242a972b 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"କୌଣସି ସାଉଣ୍ଡ କିମ୍ବା ଭାଇବ୍ରେସନ୍ ନାହିଁ"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"କୌଣସି ସାଉଣ୍ଡ କିମ୍ବା ଭାଇବ୍ରେସନ୍ ନାହିଁ ଏବଂ ବାର୍ତ୍ତାଳାପ ବିଭାଗର ନିମ୍ନରେ ଦେଖାଯାଏ"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"ଫୋନ୍ ସେଟିଂସ୍ ଆଧାରରେ ରିଙ୍ଗ କିମ୍ବା ଭାଇବ୍ରେଟ୍ ହୋଇପାରେ"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"ପ୍ରାଥମିକତା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ତଳେ ପ୍ରଦର୍ଶନ କରିଥାଏ। ସର୍ବଦା ନୀରବ।"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"ପ୍ରାଥମିକତା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ତଳେ ପ୍ରଦର୍ଶନ କରିଥାଏ। ସର୍ବଦା ନୀରବ।"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"ପ୍ରାଥମିକତା ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ତଳେ ପ୍ରଦର୍ଶନ କରିଥାଏ। ସର୍ବଦା ନୀରବ।"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"ଡିଭାଇସ୍ ଅନ୍‌ଲକ୍ ଥିବା ବେଳେ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସ୍କ୍ରିନ୍‌ର ଉପର ପାର୍ଶ୍ୱରେ ବ୍ୟାନର୍ ଭଳି ଦେଖାଯିବ"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"ସମସ୍ତ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ବିଜ୍ଞପ୍ତି"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"ସମସ୍ତ <xliff:g id="APP_NAME">%1$s</xliff:g> ବିଜ୍ଞପ୍ତି"</string>
diff --git a/res/values-pa/arrays.xml b/res/values-pa/arrays.xml
index daa8d5ad5d..7fff6a98c8 100644
--- a/res/values-pa/arrays.xml
+++ b/res/values-pa/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"ਅੰਦਰੂਨੀ ਡੀਵਾਈਸ ਸਟੋਰੇਜ"</item>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index dff9ea7bd1..a49da3a25b 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"ਕੋਈ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਹੀਂ ਅਤੇ ਸੂਚਨਾਵਾਂ ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਵਿੱਚ ਹੇਠਲੇ ਪਾਸੇ ਦਿਸਦੀਆਂ ਹਨ"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"ਫ਼ੋਨ ਸੈਟਿੰਗਾਂ ਦੇ ਆਧਾਰ \'ਤੇ ਘੰਟੀ ਵੱਜ ਸਕਦੀ ਹੈ ਜਾਂ ਥਰਥਰਾਹਟ ਹੋ ਸਕਦੀ ਹੈ"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"ਡੀਵਾਈਸ ਅਣਲਾਕ ਹੋਣ \'ਤੇ, ਸੂਚਨਾਵਾਂ ਨੂੰ ਸਕ੍ਰੀਨ ਦੇ ਸਿਖਰ \'ਤੇ ਬੈਨਰ ਵਜੋਂ ਦਿਖਾਓ"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"ਘੱਟ ਤਰਜੀਹ ਵਾਲੀਆਂ ਸੂਚਨਾਵਾਂ ਦਿਖਾਓ। ਹਮੇਸ਼ਾਂ ਖਾਮੋਸ਼।"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"ਘੱਟ ਤਰਜੀਹ ਵਾਲੀਆਂ ਸੂਚਨਾਵਾਂ ਦਿਖਾਓ। ਹਮੇਸ਼ਾਂ ਖਾਮੋਸ਼।"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"ਘੱਟ ਤਰਜੀਹ ਵਾਲੀਆਂ ਸੂਚਨਾਵਾਂ ਦਿਖਾਓ। ਹਮੇਸ਼ਾਂ ਖਾਮੋਸ਼।"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"ਸਾਰੀਆਂ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ਸੂਚਨਾਵਾਂ"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"ਸਾਰੀਆਂ <xliff:g id="APP_NAME">%1$s</xliff:g> ਸੂਚਨਾਵਾਂ"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"ਅਡੈਪਟਿਵ ਸੂਚਨਾਵਾਂ"</string>
diff --git a/res/values-pl/arrays.xml b/res/values-pl/arrays.xml
index d10c2285ca..fdba8bcbab 100644
--- a/res/values-pl/arrays.xml
+++ b/res/values-pl/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Wewnętrzna pamięć urządzenia"</item>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index c60cd4fd5e..ead8bb3e21 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -4004,6 +4004,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Brak dźwięku i wibracji"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Brak dźwięku i wibracji, wyświetla się niżej w sekcji rozmów"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Może włączyć dzwonek lub wibracje w zależności od ustawień telefonu"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Wyświetla się pod powiadomieniami priorytetowymi. Zawsze wyciszone."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Wyświetla się pod powiadomieniami priorytetowymi. Zawsze wyciszone."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Wyświetla się pod powiadomieniami priorytetowymi. Zawsze wyciszone."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Gdy urządzenie jest odblokowane, pokazuj powiadomienia jako pasek u góry ekranu"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Wszystkie powiadomienia z aplikacji „<xliff:g id="APP_NAME">%1$s</xliff:g>”"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Wszystkie powiadomienia z aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-pt-rBR/arrays.xml b/res/values-pt-rBR/arrays.xml
index e802e57096..b70a8efcfe 100644
--- a/res/values-pt-rBR/arrays.xml
+++ b/res/values-pt-rBR/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Armazenamento do dispositivo interno"</item>
diff --git a/res/values-pt-rPT/arrays.xml b/res/values-pt-rPT/arrays.xml
index 5994f66cac..4bd74a186b 100644
--- a/res/values-pt-rPT/arrays.xml
+++ b/res/values-pt-rPT/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Armazenamento de dispositivo interno"</item>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 3229e98482..444c9a60c1 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Sem som ou vibração e aparece na parte inferior na secção de conversas."</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Pode tocar ou vibrar com base nas definições do telemóvel."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Com o dispositivo desbloqueado, as notificações são apresentadas como uma faixa no topo do ecrã"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"É apresentada abaixo das notificações prioritárias. Sempre silenciosa."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"É apresentada abaixo das notificações prioritárias. Sempre silenciosa."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"É apresentada abaixo das notificações prioritárias. Sempre silenciosa."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Todas as notificações da app \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Todas as notificações da app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Notificações adaptáveis"</string>
diff --git a/res/values-pt-rPT/strings_group.xml b/res/values-pt-rPT/strings_group.xml
new file mode 100644
index 0000000000..44a330afe5
--- /dev/null
+++ b/res/values-pt-rPT/strings_group.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="group_id">Grupo ID</string>
+ <string name="refresh_group">Atualizar Grupo</string>
+ <string name="cancel_refresh_group">Cancelar atualização</string>
+ <string name="disconnect_group">Desconectar Grupo</string>
+ <string name="connect_group">Grupo de conexão</string>
+ <string name="forget_group">Grupo de conexão</string>
+ <string name="group_previously_connected_screen_title">Grupo previamente conectado</string>
+ <string name="connected_group">Grupo Conectado</string>
+ <string name="group_connected_device_media_device_title">Dispositivos Group Media</string>
+ <string name="group_settings">Grupo</string>
+ <string name="see_all_available_group">Veja todos os grupos disponíveis</string>
+ <string name="previous_connected_see_all_groups">Veja todos os grupos</string>
+ <string name="group_options">Opções de grupo</string>
+ <string name="group_connected_devices">Dispositivos conectados</string>
+ <string name="group_active_devices">Dispositivos Ativos</string>
+ <string name="group_bonded_devices">Dispositivo Ligado</string>
+ <string name="active">Ativa</string>
+ <string name="groupaudio_unpair_dialog_title">Esquecer o grupo ?</string>
+ <string name="groupaudio_unpair_dialog_body">Seu telefone não será mais emparelhado com o conjunto <xliff:g id="setid">%1$s</xliff:g></string>
+ <string name="groupaudio_unpair_dialog_forget_confirm_button">Esquecer Grupo</string>
+ <string name="group_apply_changes_dialog_title">Aplicar alterações para todos os membros do grupo ?</string>
+ <string name="group_confirm_dialog_body">Mesmas mudanças aplicáveis a todos os membros do grupo <xliff:g id="groupid">%1$s</xliff:g></string>
+ <string name="group_confirm_dialog_apply_button">Aplique</string>
+</resources>
diff --git a/res/values-pt/arrays.xml b/res/values-pt/arrays.xml
index e802e57096..b70a8efcfe 100644
--- a/res/values-pt/arrays.xml
+++ b/res/values-pt/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Armazenamento do dispositivo interno"</item>
diff --git a/res/values-pt/strings_group.xml b/res/values-pt/strings_group.xml
new file mode 100644
index 0000000000..44a330afe5
--- /dev/null
+++ b/res/values-pt/strings_group.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="group_id">Grupo ID</string>
+ <string name="refresh_group">Atualizar Grupo</string>
+ <string name="cancel_refresh_group">Cancelar atualização</string>
+ <string name="disconnect_group">Desconectar Grupo</string>
+ <string name="connect_group">Grupo de conexão</string>
+ <string name="forget_group">Grupo de conexão</string>
+ <string name="group_previously_connected_screen_title">Grupo previamente conectado</string>
+ <string name="connected_group">Grupo Conectado</string>
+ <string name="group_connected_device_media_device_title">Dispositivos Group Media</string>
+ <string name="group_settings">Grupo</string>
+ <string name="see_all_available_group">Veja todos os grupos disponíveis</string>
+ <string name="previous_connected_see_all_groups">Veja todos os grupos</string>
+ <string name="group_options">Opções de grupo</string>
+ <string name="group_connected_devices">Dispositivos conectados</string>
+ <string name="group_active_devices">Dispositivos Ativos</string>
+ <string name="group_bonded_devices">Dispositivo Ligado</string>
+ <string name="active">Ativa</string>
+ <string name="groupaudio_unpair_dialog_title">Esquecer o grupo ?</string>
+ <string name="groupaudio_unpair_dialog_body">Seu telefone não será mais emparelhado com o conjunto <xliff:g id="setid">%1$s</xliff:g></string>
+ <string name="groupaudio_unpair_dialog_forget_confirm_button">Esquecer Grupo</string>
+ <string name="group_apply_changes_dialog_title">Aplicar alterações para todos os membros do grupo ?</string>
+ <string name="group_confirm_dialog_body">Mesmas mudanças aplicáveis a todos os membros do grupo <xliff:g id="groupid">%1$s</xliff:g></string>
+ <string name="group_confirm_dialog_apply_button">Aplique</string>
+</resources>
diff --git a/res/values-ro/arrays.xml b/res/values-ro/arrays.xml
index a8c65450b5..5fc30a9701 100644
--- a/res/values-ro/arrays.xml
+++ b/res/values-ro/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Stocare internă pe dispozitiv"</item>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 229096ec26..0bf04311b0 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -3961,6 +3961,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Fără sunet sau vibrații și apare în partea de jos a secțiunii de conversație"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Poate să sune sau să vibreze, în funcție de setările telefonului"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Când dispozitivul este deblocat, afișează notificările ca un banner în partea de sus a ecranului"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Se afișează sub notificările prioritare. Întotdeauna silențios."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Se afișează sub notificările prioritare. Întotdeauna silențios."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Se afișează sub notificările prioritare. Întotdeauna silențios."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Toate notificările din „<xliff:g id="APP_NAME">%1$s</xliff:g>”"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Toate notificările din <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Notificări adaptive"</string>
diff --git a/res/values-ru/arrays.xml b/res/values-ru/arrays.xml
index e2ade5d33f..2ce985b2d2 100644
--- a/res/values-ru/arrays.xml
+++ b/res/values-ru/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Внутренний накопитель устройства"</item>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 1e128ee99f..aef23a1859 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -4004,6 +4004,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Без звука и вибрации"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Без звука или вибрации, появляется в нижней части списка разговоров"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Звонок или вибрация в зависимости от настроек телефона"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Показ уведомлений с низким приоритетом. Всегда без звука."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Показ уведомлений с низким приоритетом. Всегда без звука."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Показ уведомлений с низким приоритетом. Всегда без звука."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"При разблокированном устройстве показывать уведомления в виде баннера в верхней части экрана"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"<xliff:g id="APP_NAME">%1$s</xliff:g>: все уведомления"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Показывать все уведомления приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
diff --git a/res/values-si/arrays.xml b/res/values-si/arrays.xml
index 207c582417..6f849e1e8f 100644
--- a/res/values-si/arrays.xml
+++ b/res/values-si/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"අභ්‍යන්තර උපාංග ආචයනය"</item>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 3b8aa8e919..8e6f552578 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"හඬක් හෝ කම්පනයක් නැත"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"හඬක් හෝ කම්පනයක් නැති අතර සංවාද කොටසේ පහළම දිස් වේ"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"දුරකථන සැකසීම් මත පදනම්ව නාද කිරීමට හෝ කම්පනය කිරීමට හැකිය"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"ප්‍රමුඛතා දැනුම්දීම්වලට පහළින් සංදර්ශන වෙයි. සැම විටම නිහඬයි."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"ප්‍රමුඛතා දැනුම්දීම්වලට පහළින් සංදර්ශන වෙයි. සැම විටම නිහඬයි."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"ප්‍රමුඛතා දැනුම්දීම්වලට පහළින් සංදර්ශන වෙයි. සැම විටම නිහඬයි."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"උපාංගය අඟුලු අරිනු ලැබූ විට, තිරයේ මුදුනින් දැනුම්දීම් බැනරයක් ලෙස පෙන්වන්න"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"සියලු \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" දැනුම් දීම්"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"සියලු <xliff:g id="APP_NAME">%1$s</xliff:g> දැනුම් දීම්"</string>
diff --git a/res/values-sk/arrays.xml b/res/values-sk/arrays.xml
index 0c9e75d3a3..600800d37f 100644
--- a/res/values-sk/arrays.xml
+++ b/res/values-sk/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Interné úložisko zariadenia"</item>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 3f699fc281..f717d57c48 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -4006,6 +4006,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Žiadny zvuk ani vibrácie"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Žiadny zvuk ani vibrácie a zobrazuje sa nižšie v sekcii konverzácií"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Zvoní či vibruje podľa nastavení telefónu"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Zobrazuje sa pod prioritnými upozorneniami. Vždy potichu."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Zobrazuje sa pod prioritnými upozorneniami. Vždy potichu."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Zobrazuje sa pod prioritnými upozorneniami. Vždy potichu."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Keď je zariadenie odomknuté, zobrazovať upozornenia ako banner v hornej časti obrazovky"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Všetky upozornenia aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Všetky upozornenia aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-sl/arrays.xml b/res/values-sl/arrays.xml
index 58223f08cd..6434393845 100644
--- a/res/values-sl/arrays.xml
+++ b/res/values-sl/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Notranji pomnilnik naprave"</item>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index a4f76837c4..3594a89ee6 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -4007,6 +4007,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Brez zvočnega opozarjanja ali vibriranja, prikaz nižje v razdelku Pogovor."</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Zvonjenje ali vibriranje je omogočeno na podlagi nastavitev telefona."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Kadar je naprava odklenjena, so obvestila prikazana kot pasica na vrhu zaslona."</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Prikaz pod prednostnimi obvestili. Vedno tiho."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Prikaz pod prednostnimi obvestili. Vedno tiho."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Prikaz pod prednostnimi obvestili. Vedno tiho."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Vsa obvestila aplikacije »<xliff:g id="APP_NAME">%1$s</xliff:g>«"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Vsa obvestila aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Prilagodljiva obvestila"</string>
diff --git a/res/values-sq/arrays.xml b/res/values-sq/arrays.xml
index 2bd9b766e2..e4ff4f7b26 100644
--- a/res/values-sq/arrays.xml
+++ b/res/values-sq/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Hapësira e brendshme ruajtëse e pajisjes"</item>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index a39ba5fbbb..b44f67dad7 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Asnjë tingull ose dridhje"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Asnjë tingull ose dridhje dhe shfaqet më poshtë në seksionin e bisedave"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Mund të bjerë zilja ose të dridhet në bazë të cilësimeve të telefonit"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Shfaqet nën njoftimet me përparësi. Gjithmonë në heshtje."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Shfaqet nën njoftimet me përparësi. Gjithmonë në heshtje."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Shfaqet nën njoftimet me përparësi. Gjithmonë në heshtje."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Kur pajisja është e shkyçur, shfaq njoftimet si një banderolë përgjatë kreut të ekranit"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Të gjitha njoftimet e \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Të gjitha njoftimet e <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-sr/arrays.xml b/res/values-sr/arrays.xml
index 8cbd3637ec..f4ea8ab33c 100644
--- a/res/values-sr/arrays.xml
+++ b/res/values-sr/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Складиште унутрашњег уређаја"</item>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 218cbc9533..0d87276f86 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -3958,6 +3958,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Без звука и вибрирања"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Без звука и вибрирања и приказује се у наставку одељка за конверзације"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Може да звони или вибрира у зависности од подешавања телефона"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Приказује се испод приоритетних обавештења. Увек нечујно."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Приказује се испод приоритетних обавештења. Увек нечујно."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Приказује се испод приоритетних обавештења. Увек нечујно."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Када је уређај откључан, приказује обавештења као банер у врху екрана"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Сва обавештења апликације <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Сва обавештења апликације <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-sv/arrays.xml b/res/values-sv/arrays.xml
index 15ca538565..b05ad454d0 100644
--- a/res/values-sv/arrays.xml
+++ b/res/values-sv/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Lagring på intern enhet"</item>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 82526a686b..6af8c4bb74 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Inga ljud eller vibrationer"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Inga ljud eller vibrationer och visas längre ned bland konversationerna"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Kan ringa eller vibrera beroende på inställningarna på telefonen"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Aviseringar med låg prioritet visas. Alltid tyst."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Aviseringar med låg prioritet visas. Alltid tyst."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Aviseringar med låg prioritet visas. Alltid tyst."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"När enheten är olåst visas aviseringar i en banner högst upp på skärmen"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Alla aviseringar från <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Alla aviseringar från <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-sw/arrays.xml b/res/values-sw/arrays.xml
index b3ebf18d20..13462fd25c 100644
--- a/res/values-sw/arrays.xml
+++ b/res/values-sw/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Kifaa cha hifadhi ya ndani"</item>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index e5b5f646b2..4497c6f971 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Hakuna sauti wala mtetemo na huonekana upande wa chini katika sehemu ya mazungumzo"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Huenda ikalia au kutetema kulingana na mipangilio ya simu"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Wakati kifaa kimefunguliwa, onyesha arifa kama bango katika sehemu ya juu ya skrini"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Huonyeshwa chini ya arifa za kipaumbele. Kimya kila wakati."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Huonyeshwa chini ya arifa za kipaumbele. Kimya kila wakati."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Huonyeshwa chini ya arifa za kipaumbele. Kimya kila wakati."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Arifa zote za \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Arifa zote za <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Arifa Zinazojirekebisha"</string>
diff --git a/res/values-ta/arrays.xml b/res/values-ta/arrays.xml
index fb62e80e92..67dcb16e62 100644
--- a/res/values-ta/arrays.xml
+++ b/res/values-ta/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"சாதன அகச் சேமிப்பு"</item>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 727ec7b5b9..526a689027 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"ஒலி / அதிர்வு இல்லை"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"ஒலி / அதிர்வு இல்லாமல் உரையாடல் பிரிவின் கீழ்ப் பகுதியில் தோன்றும்"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"மொபைல் அமைப்புகளின் அடிப்படையில் ஒலிக்கவோ அதிரவோ செய்யும்"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"முக்கியத்துவம் குறைந்த அறிவிப்புகளைக் காட்டும். எப்போதும் நிசப்தம்."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"முக்கியத்துவம் குறைந்த அறிவிப்புகளைக் காட்டும். எப்போதும் நிசப்தம்."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"முக்கியத்துவம் குறைந்த அறிவிப்புகளைக் காட்டும். எப்போதும் நிசப்தம்."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"மொபைல் அன்லாக் செய்யப்பட்ட நிலையிலிருக்கும்போது அறிவிப்புகளைத் திரையின் மேல் பகுதியில் பேனராகக் காட்டும்"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"அனைத்து \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" அறிவிப்புகளும்"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"அனைத்து <xliff:g id="APP_NAME">%1$s</xliff:g> அறிவிப்புகளும்"</string>
diff --git a/res/values-te/arrays.xml b/res/values-te/arrays.xml
index e264c25e44..20bbfe856b 100644
--- a/res/values-te/arrays.xml
+++ b/res/values-te/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"అంతర్గత పరికర నిల్వ"</item>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 5e761495d2..3859cbcb40 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"శబ్దం లేదా వైబ్రేషన్ లేదు, సంభాషణ విభాగం దిగువన కనిపిస్తుంది"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"ఫోన్ సెట్టింగ్‌ల ఆధారంగా రింగ్ లేదా వైబ్రేట్ కావచ్చు"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"పరికరాన్ని అన్‌లాక్ చేసినప్పుడు స్క్రీన్ పైభాగంలో ఒక‌ బ్యానర్‌గా నోటిఫికేషన్‌లను చూపించు"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"తక్కువ ప్రాధాన్యత గల నోటిఫికేషన్‌లను ప్రదర్శిస్తుంది. ఎల్లప్పుడూ నిశ్శబ్దంగా ఉంచుతుంది."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"తక్కువ ప్రాధాన్యత గల నోటిఫికేషన్‌లను ప్రదర్శిస్తుంది. ఎల్లప్పుడూ నిశ్శబ్దంగా ఉంచుతుంది."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"తక్కువ ప్రాధాన్యత గల నోటిఫికేషన్‌లను ప్రదర్శిస్తుంది. ఎల్లప్పుడూ నిశ్శబ్దంగా ఉంచుతుంది."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" నోటిఫికేషన్‌లన్నీ"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"అన్ని <xliff:g id="APP_NAME">%1$s</xliff:g> నోటిఫికేషన్‌లు"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"అనుకూల నోటిఫికేషన్‌లు"</string>
diff --git a/res/values-th/arrays.xml b/res/values-th/arrays.xml
index bc399ab1ea..976ecf6a09 100644
--- a/res/values-th/arrays.xml
+++ b/res/values-th/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"ที่จัดเก็บข้อมูลอุปกรณ์ภายใน"</item>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 44d61dd9ff..e78e7dfb54 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"ไม่มีเสียงหรือการสั่น"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"ไม่มีเสียงหรือการสั่น และปรากฏต่ำลงมาในส่วนการสนทนา"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"อาจส่งเสียงหรือสั่นโดยขึ้นอยู่กับการตั้งค่าโทรศัพท์"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"แสดงใต้การแจ้งเตือนเรื่องสำคัญ ปิดเสียงตลอดเวลา"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"แสดงใต้การแจ้งเตือนเรื่องสำคัญ ปิดเสียงตลอดเวลา"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"แสดงใต้การแจ้งเตือนเรื่องสำคัญ ปิดเสียงตลอดเวลา"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"เมื่ออุปกรณ์ปลดล็อกอยู่ ให้แสดงการแจ้งเตือนเป็นแบนเนอร์ที่ด้านบนของหน้าจอ"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"การแจ้งเตือนทั้งหมดของ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"การแจ้งเตือนทั้งหมดของ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-tl/arrays.xml b/res/values-tl/arrays.xml
index 0e5344fd42..4e4ce9a173 100644
--- a/res/values-tl/arrays.xml
+++ b/res/values-tl/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Storage ng panloob na device"</item>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 0589f55f35..ab16401ec2 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Walang tunog o pag-vibrate"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Walang tunog o pag-vibrate at lumalabas nang mas mababa sa seksyon ng pag-uusap"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Puwedeng mag-ring o mag-vibrate batay sa mga setting ng telepono"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Ipinapakita sa ibaba ng mga priyoridad na notification. Palaging naka-silent."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Ipinapakita sa ibaba ng mga priyoridad na notification. Palaging naka-silent."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Ipinapakita sa ibaba ng mga priyoridad na notification. Palaging naka-silent."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Kapag naka-unlock ang device, ipakita ang mga notification bilang banner sa itaas ng screen"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Lahat ng notification ng \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Lahat ng notification ng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-tr/arrays.xml b/res/values-tr/arrays.xml
index 29c460d2e1..f17a82d6f9 100644
--- a/res/values-tr/arrays.xml
+++ b/res/values-tr/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Dahili cihaz depolaması"</item>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 267be6196e..b222634197 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Sessiz veya titreşim yok"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Sessizdir veya titreşim yoktur ve görüşme bölümünün altında görünür"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Telefon ayarlarına bağlı olarak zili çalabilir veya titreyebilir"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Öncelikli bildirimlerin altında gösterilir. Her zaman sessiz."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Öncelikli bildirimlerin altında gösterilir. Her zaman sessiz."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Öncelikli bildirimlerin altında gösterilir. Her zaman sessiz."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Cihaz kilitli değilken, bildirimleri ekranın üst kısmında banner olarak göster"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Tüm \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" bildirimleri"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Tüm <xliff:g id="APP_NAME">%1$s</xliff:g> bildirimleri"</string>
diff --git a/res/values-uk/arrays.xml b/res/values-uk/arrays.xml
index 6200fd12eb..27fc5e71f5 100644
--- a/res/values-uk/arrays.xml
+++ b/res/values-uk/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Внутрішня пам\'ять пристрою"</item>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index d63be1d64f..e860053f8a 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -4004,6 +4004,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Без звуку чи вібрації"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Без звуку чи вібрації, з\'являється нижче в розділі розмов"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Може дзвонити або вібрувати залежно від налаштувань телефона"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Показуються під пріоритетними сповіщеннями. Завжди без звуку."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Показуються під пріоритетними сповіщеннями. Завжди без звуку."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Показуються під пріоритетними сповіщеннями. Завжди без звуку."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Коли пристрій розблоковано, показувати сповіщення як банер угорі екрана"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"<xliff:g id="APP_NAME">%1$s</xliff:g>: усі сповіщення"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Усі сповіщення від додатка <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-ur/arrays.xml b/res/values-ur/arrays.xml
index cab4c4b2f7..f018bcb0ee 100644
--- a/res/values-ur/arrays.xml
+++ b/res/values-ur/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"آلہ کا داخلی اسٹوریج"</item>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index d50bbd8931..979e2d64d6 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -3912,6 +3912,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"کوئی آواز یا وائبریشن نہیں"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"کوئی آواز یا وائبریشن نہیں اور گفتگو کے سیکشن میں نیچے ظاہر ہوتا ہے"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"آپ کے آلہ کی ترتیبات کے مطابق وائبریٹ یا گھنٹی بج سکتی ہے"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"کم ترجیحی اطلاعات ڈسپلے کرتا ہے۔ ہمیشہ خاموش۔"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"کم ترجیحی اطلاعات ڈسپلے کرتا ہے۔ ہمیشہ خاموش۔"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"کم ترجیحی اطلاعات ڈسپلے کرتا ہے۔ ہمیشہ خاموش۔"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"آلہ کے غیر مقفل ہو جانے پر، اطلاعات کو اسکرین کے اوپر بینر کے طور پر دکھائيں"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"سبھی \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" کی اطلاعات"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"سبھی <xliff:g id="APP_NAME">%1$s</xliff:g> اطلاعات"</string>
diff --git a/res/values-uz/arrays.xml b/res/values-uz/arrays.xml
index 58bd2de734..e835a5b25f 100644
--- a/res/values-uz/arrays.xml
+++ b/res/values-uz/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Ichki xotira qurilmasi"</item>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 6973cdd76f..6111552394 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -3915,6 +3915,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Tovush yoki tebranishsiz hamda suhbatlar ruknining pastida chiqadi"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Telefon sozlamalari asosida jiringlashi yoki tebranishi mumkin"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Telefon ochiqligida bildirishnomalar ekranning yuqori qismida banner sifatida chiqadi"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Muhimlik darajasi past bildirishnomalarning chiqishi. Doim tovushsiz."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Muhimlik darajasi past bildirishnomalarning chiqishi. Doim tovushsiz."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Muhimlik darajasi past bildirishnomalarning chiqishi. Doim tovushsiz."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Barcha <xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnomalari"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Barcha <xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnomalari"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Moslashuvchan bildirishnomalar"</string>
diff --git a/res/values-vi/arrays.xml b/res/values-vi/arrays.xml
index 867438892b..2699c9f075 100644
--- a/res/values-vi/arrays.xml
+++ b/res/values-vi/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Bộ nhớ trong của thiết bị"</item>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 8e055c8ced..9cc185ceec 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -3915,6 +3915,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Không phát âm thanh hoặc rung và xuất hiện phía dưới trong phần cuộc trò chuyện"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Có thể đổ chuông hoặc rung tùy theo chế độ cài đặt trên điện thoại"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Hiện thông báo ở đầu màn hình khi thiết bị đang mở khóa"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Hiển thị bên dưới thông báo mức độ ưu tiên. Luôn im lặng."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Hiển thị bên dưới thông báo mức độ ưu tiên. Luôn im lặng."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Hiển thị bên dưới thông báo mức độ ưu tiên. Luôn im lặng."</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Tất cả các thông báo của ứng dụng \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Tất cả thông báo của <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"Thông báo thích ứng"</string>
diff --git a/res/values-zh-rCN/arrays.xml b/res/values-zh-rCN/arrays.xml
index 3b9dcf5514..acfacff36b 100644
--- a/res/values-zh-rCN/arrays.xml
+++ b/res/values-zh-rCN/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"内部存储设备"</item>
@@ -589,4 +590,10 @@
<!-- no translation found for rtt_setting_mode:1 (7903019313228349427) -->
<!-- no translation found for rtt_setting_mode:2 (8525285145696236811) -->
<!-- no translation found for rtt_setting_mode:3 (7725394146877517088) -->
+ <string-array name="preferred_5g_network_mode_choices">
+ <item>NSA 模式</item>
+ <item>SA 模式</item>
+ <item>NSA + SA 模式</item>
+ </string-array>
+
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 3a2aa125ef..777d82c6e2 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -3428,6 +3428,8 @@
<string name="contact_discovery_opt_in_dialog_message_no_carrier_defined" msgid="1914894516552445911">"系统会定期将您的联系人电话号码发送给您的运营商。<xliff:g id="EMPTY_LINE">
</xliff:g>此信息可用于识别您的联系人能否使用特定功能,例如视频通话或某些消息传递功能。"</string>
+ <!-- Enabled 5G Mode title. [CHAR LIMIT=50] -->
+ <string name="enabled_5g_mode_title">启用5G</string>
<string name="preferred_network_type_title" msgid="812509938714590857">"首选网络类型"</string>
<string name="preferred_network_type_summary" msgid="8786291927331323061">"LTE(推荐)"</string>
<string name="mms_message_title" msgid="6624505196063391964">"彩信"</string>
@@ -3640,6 +3642,7 @@
<string name="spatial_audio_title" msgid="6591051622375191603">"空间音频"</string>
<string name="dial_pad_tones_title" msgid="3536945335367914892">"拨号键盘提示音"</string>
<string name="screen_locking_sounds_title" msgid="5695030983872787321">"屏幕锁定提示音"</string>
+ <string name="call_connected_tones_title" msgid="1999293510400911558">"通话接通提示音"</string>
<string name="charging_sounds_title" msgid="5261683808537783668">"充电提示音和振动"</string>
<string name="docking_sounds_title" msgid="5341616179210436159">"基座提示音"</string>
<string name="touch_sounds_title" msgid="2200734041857425078">"触摸提示音"</string>
@@ -3912,6 +3915,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"不发出提示音,也不振动"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"不发出提示音,也不振动;显示在对话部分的靠下位置"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"可能会响铃或振动(取决于手机设置)"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"显示在优先通知下方。一律不发出提示音。"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"显示在优先通知下方。一律不发出提示音。"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"显示在优先通知下方。一律不发出提示音。"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"当设备处于解锁状态时,在屏幕顶端以横幅形式显示通知"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"所有“<xliff:g id="APP_NAME">%1$s</xliff:g>”通知"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"<xliff:g id="APP_NAME">%1$s</xliff:g>的所有通知"</string>
@@ -5091,6 +5097,18 @@
<string name="platform_compat_default_disabled_title" msgid="3975847180953793602">"默认停用的应用兼容性变更"</string>
<string name="platform_compat_dialog_title_no_apps" msgid="4387656000745989506">"没有可用的应用"</string>
<string name="platform_compat_dialog_text_no_apps" msgid="5715226015751055812">"只能修改可调试应用的应用兼容性变更。请安装可调试的应用,然后重试。"</string>
+ <!-- apn names for carriers -->
+ <string name="APN_NAME_CMNET">中国移动NET</string>
+ <string name="APN_NAME_CMWAP">中国移动WAP</string>
+ <string name="APN_NAME_CMMMS">中国移动彩信设置</string>
+ <string name="APN_NAME_CUWAP">沃宽带用户手机上网</string>
+ <string name="APN_NAME_CUNET">沃宽带用户连接互联网</string>
+ <string name="APN_NAME_CUMMS">联通彩信</string>
+ <string name="APN_NAME_CUSUPL">联通AGPS</string>
+ <string name="APN_NAME_CTNET">中国电信互联网设置 CTNET</string>
+ <string name="APN_NAME_CTWAP">中国电信WAP设置 CTWAP</string>
+ <string name="APN_NAME_CTLTE">中国电信互联网设置 ctlte</string>
+ <string name="APN_NAME_CTMMS">中国电信彩信设置 CTWAP</string>
<string name="unsupported_setting_summary" product="default" msgid="1085229417771470172">"此手机不支持这项设置"</string>
<string name="unsupported_setting_summary" product="tablet" msgid="7402414129786489664">"此平板电脑不支持这项设置"</string>
<string name="unsupported_setting_summary" product="device" msgid="3422953459122926833">"此设备不支持这项设置"</string>
@@ -5206,7 +5224,9 @@
<string name="mobile_data_settings_title" msgid="3927524078598009792">"移动数据"</string>
<string name="mobile_data_settings_summary" msgid="7323978798199919063">"通过移动网络访问数据"</string>
<string name="mobile_data_settings_summary_auto_switch" msgid="7851549787645698945">"手机会在进入有效范围时自动切换到此运营商"</string>
+ <string name="data_preference">"数据偏好设置"</string>
<string name="mobile_data_settings_summary_unavailable" msgid="3309106501029928951">"没有可用的 SIM 卡"</string>
+ <string name="mobile_data_settings_summary_default_data_unavailable">"通话挂断后数据会自动切换到此运营商"</string>
<string name="calls_preference" msgid="2166481296066890129">"通话偏好设置"</string>
<string name="sms_preference" msgid="7742964962568219351">"短信偏好设置"</string>
<string name="calls_and_sms_ask_every_time" msgid="3178743088737726677">"每次都询问"</string>
@@ -5580,4 +5600,7 @@
<string name="bluetooth_connect_access_dialog_content" msgid="4336436466468405850">"“<xliff:g id="DEVICE_NAME_0">%1$s</xliff:g>”想连接到此手机。\n\n您之前没有连接过“<xliff:g id="DEVICE_NAME_1">%2$s</xliff:g>”。"</string>
<string name="bluetooth_connect_access_dialog_negative" msgid="4944672755226375059">"不连接"</string>
<string name="bluetooth_connect_access_dialog_positive" msgid="3630561675207269710">"连接"</string>
+ <string name="prefer_5G_nr_mode_title">首选5G模式</string>
+ <string name="prefer_vonr_mode_title">打开/关闭 VoNR</string>
+ <string name="prefer_vonr_mode_summary">打开或者关闭VoNR</string>
</resources>
diff --git a/res/values-zh-rCN/strings_group.xml b/res/values-zh-rCN/strings_group.xml
new file mode 100644
index 0000000000..6dbd4bead2
--- /dev/null
+++ b/res/values-zh-rCN/strings_group.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="group_id">組號</string>
+ <string name="refresh_group">刷新组</string>
+ <string name="cancel_refresh_group">取消刷新</string>
+ <string name="disconnect_group">断开群组</string>
+ <string name="connect_group">连接组</string>
+ <string name="forget_group">忘记组</string>
+ <string name="group_previously_connected_screen_title">先前连接的组</string>
+ <string name="connected_group">连接组</string>
+ <string name="group_settings">组</string>
+ <string name="previously_connected_group_screen_title">先前连接的组</string>
+ <string name="previous_connected_see_all_groups">查看所有组</string>
+ <string name="group_options">组选项</string>
+ <string name="group_connected_devices">联网设备</string>
+ <string name="group_active_devices">有源设备</string>
+ <string name="group_bonded_devices">绑定设备</string>
+ <string name="active">活性</string>
+ <string name="groupaudio_unpair_dialog_title">忘记群组 ?</string>
+ <string name="groupaudio_unpair_dialog_body">您的手机将不再与手机配对 <xliff:g id="setid">%1$s</xliff:g></string>
+ <string name="groupaudio_unpair_dialog_forget_confirm_button">忘记组</string>
+ <string name="group_apply_changes_dialog_title">是否为所有小组成员应用更改?</string>
+ <string name="group_confirm_dialog_body">适用于组中所有成员的相同更改 <xliff:g id="groupid">%1$s</xliff:g></string>
+ <string name="group_confirm_dialog_apply_button"></string>
+</resources>
diff --git a/res/values-zh-rHK/arrays.xml b/res/values-zh-rHK/arrays.xml
index a06b840d51..4d26ccb7a7 100644
--- a/res/values-zh-rHK/arrays.xml
+++ b/res/values-zh-rHK/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"內部裝置儲存空間"</item>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 5ebad90a1c..e8baf22006 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -3916,6 +3916,9 @@
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"無音效或震動,並在對話部分的較低位置顯示"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"根據手機設定發出鈴聲或震動"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"裝置處於解鎖狀態時,在螢幕頂部以橫額格式顯示通知"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"顯示不重要的通知。一律靜音。"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"顯示不重要的通知。一律靜音。"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"顯示不重要的通知。一律靜音。"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"所有「<xliff:g id="APP_NAME">%1$s</xliff:g>」通知"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"所有「<xliff:g id="APP_NAME">%1$s</xliff:g>」通知"</string>
<string name="default_notification_assistant" msgid="243718059890346442">"自動調節通知"</string>
diff --git a/res/values-zh-rHK/strings_group.xml b/res/values-zh-rHK/strings_group.xml
new file mode 100644
index 0000000000..73ca703f1e
--- /dev/null
+++ b/res/values-zh-rHK/strings_group.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="group_id">組號</string>
+ <string name="refresh_group">刷新组</string>
+ <string name="cancel_refresh_group">取消刷新</string>
+ <string name="disconnect_group">断开群组</string>
+ <string name="connect_group">连接组</string>
+ <string name="forget_group">忘记组</string>
+ <string name="group_previously_connected_screen_title">先前连接的组</string>
+ <string name="connected_group">连接组</string>
+ <string name="group_settings">组</string>
+ <string name="previously_connected_group_screen_title">先前连接的组</string>
+ <string name="previous_connected_see_all_groups">查看所有组</string>
+ <string name="group_options">组选项</string>
+ <string name="group_connected_devices">联网设备</string>
+ <string name="group_active_devices">有源设备</string>
+ <string name="group_bonded_devices">绑定设备</string>
+ <string name="active">活性</string>
+ <string name="groupaudio_unpair_dialog_title">忘记群组 ?</string>
+ <string name="groupaudio_unpair_dialog_body">您的手机将不再与手机配对 <xliff:g id="setid">%1$s</xliff:g></string>
+ <string name="groupaudio_unpair_dialog_forget_confirm_button">忘记组</string>
+ <string name="group_apply_changes_dialog_title">是否为所有小组成员应用更改?</string>
+ <string name="group_confirm_dialog_body">适用于组中所有成员的相同更改 <xliff:g id="groupid">%1$s</xliff:g></string>
+ <string name="group_confirm_dialog_apply_button">应用</string>
+</resources>
diff --git a/res/values-zh-rTW/arrays.xml b/res/values-zh-rTW/arrays.xml
index 347c447784..36b572fef3 100644
--- a/res/values-zh-rTW/arrays.xml
+++ b/res/values-zh-rTW/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"內部裝置儲存空間"</item>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 57c09d1304..e35bbc6895 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -3914,6 +3914,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"不震動或發出聲音"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"不震動或發出聲音,並顯示在對話區的下方"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"根據手機的設定響鈴或震動"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"顯示在優先通知下方,且一律不發出音效。"</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"顯示在優先通知下方,且一律不發出音效。"</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"顯示在優先通知下方,且一律不發出音效。"</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"裝置處於解鎖狀態時,在螢幕頂端以橫幅形式顯示通知"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的所有通知"</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的所有通知"</string>
diff --git a/res/values-zh-rTW/strings_group.xml b/res/values-zh-rTW/strings_group.xml
new file mode 100644
index 0000000000..73ca703f1e
--- /dev/null
+++ b/res/values-zh-rTW/strings_group.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="group_id">組號</string>
+ <string name="refresh_group">刷新组</string>
+ <string name="cancel_refresh_group">取消刷新</string>
+ <string name="disconnect_group">断开群组</string>
+ <string name="connect_group">连接组</string>
+ <string name="forget_group">忘记组</string>
+ <string name="group_previously_connected_screen_title">先前连接的组</string>
+ <string name="connected_group">连接组</string>
+ <string name="group_settings">组</string>
+ <string name="previously_connected_group_screen_title">先前连接的组</string>
+ <string name="previous_connected_see_all_groups">查看所有组</string>
+ <string name="group_options">组选项</string>
+ <string name="group_connected_devices">联网设备</string>
+ <string name="group_active_devices">有源设备</string>
+ <string name="group_bonded_devices">绑定设备</string>
+ <string name="active">活性</string>
+ <string name="groupaudio_unpair_dialog_title">忘记群组 ?</string>
+ <string name="groupaudio_unpair_dialog_body">您的手机将不再与手机配对 <xliff:g id="setid">%1$s</xliff:g></string>
+ <string name="groupaudio_unpair_dialog_forget_confirm_button">忘记组</string>
+ <string name="group_apply_changes_dialog_title">是否为所有小组成员应用更改?</string>
+ <string name="group_confirm_dialog_body">适用于组中所有成员的相同更改 <xliff:g id="groupid">%1$s</xliff:g></string>
+ <string name="group_confirm_dialog_apply_button">应用</string>
+</resources>
diff --git a/res/values-zu/arrays.xml b/res/values-zu/arrays.xml
index e3bd1fee6e..38bac00a02 100644
--- a/res/values-zu/arrays.xml
+++ b/res/values-zu/arrays.xml
@@ -214,6 +214,7 @@
<item msgid="8568003268185342352">"SPN"</item>
<item msgid="1804537219968457989">"IMSI"</item>
<item msgid="3441876902463317017">"GID"</item>
+ <item>ICCID</item>
</string-array>
<string-array name="app_install_location_entries">
<item msgid="3771157789865587832">"Isitoreji sedivaysi yangaphakathi"</item>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 703b34e385..ae13c192c8 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -3913,6 +3913,9 @@
<string name="notification_channel_summary_low" msgid="5549662596677692000">"Awukho umsindo noma ukudlidliza"</string>
<string name="notification_conversation_summary_low" msgid="6352818857388412326">"Awukho umsindo noma ukudlidliza futhi ivela ngezansi esigabeni sengxoxo"</string>
<string name="notification_channel_summary_default" msgid="3674057458265438896">"Ingase ikhale noma idlidlize kuya ngamasethingi wefoni yakho"</string>
+ <string name="notification_channel_summary_low_status" msgid="7866565328564018007">"Ibonisa izaziso ezibalulekile ezingezansi. Ihlala ithulile."</string>
+ <string name="notification_channel_summary_low_lock" msgid="4009247523075328235">"Ibonisa izaziso ezibalulekile ezingezansi. Ihlala ithulile."</string>
+ <string name="notification_channel_summary_low_status_lock" msgid="3668028634045057230">"Ibonisa izaziso ezibalulekile ezingezansi. Ihlala ithulile."</string>
<string name="notification_channel_summary_high" msgid="3411637309360617621">"Uma idivayisi ivuliwe, bonisa izaziso njengesibhengezo ngaphezulu kwesikrini"</string>
<string name="notification_switch_label" msgid="8029371325967501557">"Zonke izaziso ze-\"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="notification_app_switch_label" msgid="4422902423925084193">"Zonke izaziso ze-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 0fe13feb3e..feccba4fa0 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -229,6 +229,8 @@
<!-- Do not translate. -->
<item>@string/wifi_security_wpa2</item>
<!-- Do not translate. -->
+ <item>@string/wifi_security_owe</item>
+ <!-- Do not translate. -->
<item>@string/wifi_security_none</item>
</string-array>
@@ -241,6 +243,8 @@
<!-- Do not translate. -->
<item>1</item>
<!-- Do not translate. -->
+ <item>4</item>
+ <!-- Do not translate. -->
<item>0</item>
</string-array>
@@ -352,6 +356,20 @@
<item>5</item>
</string-array>
+ <!-- Bluetooth broadcast pin: Titles for Pin configuration -->
+ <string-array translatable="false" name="bluetooth_broadcast_pin_config_titles">
+ <item>Unencrypted (no security)</item>
+ <item>4 digit pin (low security)</item>
+ <item>16 digit pin (high security)</item>
+ </string-array>
+
+ <!-- Bluetooth broadcast pin: Values for Pin configuration -->
+ <string-array translatable="false" name="bluetooth_broadcast_pin_config_values">
+ <item>0</item>
+ <item>4</item>
+ <item>16</item>
+ </string-array>
+
<!-- Match this with drawable.wifi_signal. --> <skip />
<!-- Wi-Fi settings. The signal strength a Wi-Fi network has. -->
<string-array name="wifi_signal">
@@ -521,12 +539,25 @@
<item>20</item>
</string-array>
+ <string-array name="preferred_5g_network_mode_choices">
+ <item>NSA Mode</item>
+ <item>SA Mode</item>
+ <item>NSA + SA Mode</item>
+ </string-array>
+
+ <string-array name="preferred_5g_network_mode_values" translatable="false">
+ <item>"1"</item>
+ <item>"2"</item>
+ <item>"0"</item>
+ </string-array>
+
<!-- MVNO Info used in APN editor -->
<string-array name="mvno_type_entries">
<item>None</item>
<item translatable="false">SPN</item>
<item translatable="false">IMSI</item>
<item translatable="false">GID</item>
+ <item translatable="false">ICCID</item>
</string-array>
<string-array translatable="false" name="mvno_type_values">
@@ -538,6 +569,8 @@
<item>imsi</item>
<!-- Do not translate. -->
<item>gid</item>
+ <!-- Do not translate. -->
+ <item>iccid</item>
</string-array>
<!-- Apps on SD installation location options in ApplicationSettings -->
@@ -1503,6 +1536,39 @@
</string-array>
+ <!-- String arrays for PrimaryCard LW feature -->
+ <string-array name="preferred_network_mode_gsm_wcdma_choices">
+ <item>GSM only</item>
+ <item>WCDMA only</item>
+ <item>GSM/WCDMA preferred</item>
+ </string-array>
+ <string-array name="preferred_network_mode_gsm_wcdma_values" translatable="false">
+ <item>"1"</item>
+ <item>"2"</item>
+ <item>"0"</item>
+ </string-array>
+
+ <string-array name="enabled_networks_gsm_wcdma_choices">
+ <item>@string/network_2G_only</item>
+ <item>@string/network_3G_only</item>
+ <item>@string/network_2G_3G_preferred</item>
+ </string-array>
+ <string-array name="enabled_networks_gsm_wcdma_values" translatable="false">
+ <item>"1"</item>
+ <item>"2"</item>
+ <item>"0"</item>
+ </string-array>
+
+ <!-- String arrays for Subsidy Lock feature -->
+ <string-array name="enabled_networks_subsidy_locked_choices">
+ <item>LTE Only</item>
+ <item>GSM/WCDMA/LTE</item>
+ </string-array>
+ <string-array name="enabled_networks_subsidy_locked_values" translatable="false">
+ <item>"11"</item>
+ <item>"9"</item>
+ </string-array>
+
<!-- WiFi calling mode array -->
<string-array name="wifi_calling_mode_summaries" translatable="false">
<item>@string/wifi_calling_mode_wifi_preferred_summary</item>
@@ -1510,12 +1576,27 @@
<item>@string/wifi_calling_mode_wifi_only_summary</item>
</string-array>
+ <!-- WiFi calling mode array with ims preferred -->
+ <string-array name="wifi_calling_mode_summaries_with_ims_preferred" translatable="false">
+ <item>@string/wifi_calling_mode_ims_preferred_summary</item>
+ <item>@string/wifi_calling_mode_wifi_preferred_summary</item>
+ <item>@string/wifi_calling_mode_cellular_preferred_summary</item>
+ <item>@string/wifi_calling_mode_wifi_only_summary</item>
+ </string-array>
+
<!-- WiFi calling mode array without wifi only mode -->
<string-array name="wifi_calling_mode_summaries_without_wifi_only" translatable="false">
<item>@string/wifi_calling_mode_wifi_preferred_summary</item>
<item>@string/wifi_calling_mode_cellular_preferred_summary</item>
</string-array>
+ <!-- WiFi calling mode array without wifi only mode with ims preferred -->
+ <string-array name="wifi_calling_mode_summaries_without_wifi_only_with_ims_preferred" translatable="false">
+ <item>@string/wifi_calling_mode_ims_preferred_summary</item>
+ <item>@string/wifi_calling_mode_wifi_preferred_summary</item>
+ <item>@string/wifi_calling_mode_cellular_preferred_summary</item>
+ </string-array>
+
<!-- Carrier variant of Enhaced 4G LTE Mode title. [CHAR LIMIT=NONE] -->
<string-array name="enhanced_4g_lte_mode_title_variant">
<!-- 0: Default -->
@@ -1596,4 +1677,31 @@
<item>2</item>
<item>4</item>
</string-array>
+ <!--String arrays for showing user PLMN list -->
+ <string-array name="uplmn_prefer_network_mode_td_choices">
+ <item>GSM</item>
+ <item>TDSCDMA</item>
+ <item>LTE</item>
+ <item>Triple mode</item>
+ </string-array>
+
+ <string-array name="uplmn_prefer_network_mode_w_choices">
+ <item>GSM</item>
+ <item>WCDMA</item>
+ <item>LTE</item>
+ <item>Triple mode</item>
+ </string-array>
+
+ <string-array name="uplmn_prefer_network_mode_values">
+ <item>"0"</item>
+ <item>"1"</item>
+ <item>"2"</item>
+ <item>"3"</item>
+ </string-array>
+
+ <string-array name="uplmn_cu_mcc_mnc_values">
+ <item>"46001"</item>
+ <item>"46006"</item>
+ <item>"46009"</item>
+ </string-array>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 987eaf9725..b470050c45 100755
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -455,6 +455,12 @@
<!-- Whether or not extra preview panels should be used for screen zoom setting. -->
<bool name="config_enable_extra_screen_zoom_preview">true</bool>
+ <!-- Whether to add AGPS parameter settings -->
+ <bool name="config_agps_enabled">false</bool>
+
+ <!-- Whether to support CT PA requirement or not -->
+ <bool name="config_support_CT_PA">false</bool>
+
<!-- Slice Uri to query nearby devices. -->
<string name="config_nearby_devices_slice_uri" translatable="false">content://com.google.android.gms.nearby.fastpair/device_status_list_item</string>
@@ -557,4 +563,8 @@
<!-- Whether to aggregate for network selection list-->
<bool name="config_network_selection_list_aggregation_enabled">false</bool>
+
+ <!-- Playing tone setting -->
+ <bool name="config_show_connect_tone_ui">false</bool>
+ <integer name="config_default_tone_after_connected">0</integer>
</resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 300b3a4201..ee29b88e5b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -14,6 +14,10 @@
limitations under the License.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Strings for the smart DDS switch toggle in developer options -->
+ <string name="smart_dds_switch">Smart DDS switch</string>
+ <string name="smart_dds_switch_wait_summary">Please wait...</string>
+ <string name="smart_dds_switch_summary">Allow modem to intelligently switch the DDS.</string>
<!-- Strings for Dialog yes button -->
<string name="yes">"Yes"</string>
<!-- Strings for Dialog no button -->
@@ -198,6 +202,15 @@
<!-- Bluetooth broadcasting settings, option to enable/disable broadcasting -->
<string name="bluetooth_broadcasting">Broadcasting</string>
+ <!-- Bluetooth broadcast enable/disable -->
+ <string name="bluetooth_broadcast">Broadcast</string>
+
+ <!-- Bluetooth broadcast settings -->
+ <string name="bluetooth_broadcast_pin_configure">Broadcast: Bluetooth Privacy Code</string>
+
+ <!-- Bluetooth broadcast settings -->
+ <string name="bluetooth_broadcast_pin_configure_dialog">Broadcast: Configure Bluetooth Privacy Code</string>
+
<!--Bluetooth settings screen, summary text for Bluetooth device with no name -->
<string name="bluetooth_device">Unnamed Bluetooth device</string>
<!--Bluetooth settings screen, text that appears in heading bar when scanning for devices -->
@@ -346,6 +359,8 @@
<string name="connected_device_other_device_title">Other devices</string>
<!-- Title for connected device group [CHAR LIMIT=none]-->
<string name="connected_device_saved_title">Saved devices</string>
+ <!-- Title for connected TWS device group [CHAR LIMIT=none]-->
+ <string name="connected_tws_device_saved_title">Saved Earbuds</string>
<!-- Summary for preference to add a device [CHAR LIMIT=none]-->
<string name="connected_device_add_device_summary">Bluetooth will turn on to pair</string>
<!-- Title for other connection preferences [CHAR LIMIT=none]-->
@@ -1978,6 +1993,8 @@
<string name="wifi_display_settings_title">Cast</string>
<!-- Wifi Display settings. The keywords of the setting. [CHAR LIMIT=NONE] -->
<string name="keywords_wifi_display_settings">mirror</string>
+ <!-- Checkbox title for enabling particual wifi as shared -->
+ <string name="share_this_wifi">Extend Wi-Fi coverage</string>
<!-- Wifi Display settings. The title of a menu item to enable wireless display [CHAR LIMIT=40] -->
<string name="wifi_display_enable_menu_item">Enable wireless display</string>
<!-- Wifi Display settings. Text that appears when scanning for devices is finished and no nearby device was found [CHAR LIMIT=40]-->
@@ -2026,6 +2043,8 @@
<string name="wifi_band_5ghz">5 GHz</string>
<!-- Wifi 6GHz is used as a universal identifier for 6GHz band [CHAR LIMIT=40] -->
<string name="wifi_band_6ghz">6 GHz</string>
+ <!-- Wifi Internal 60GHz as an universal identifier for 60GHz band -->
+ <string name="wifi_band_60ghz">60 GHz</string>
<!-- Wifi Sign in text for button [CHAR LIMIT = 40]-->
<string name="wifi_sign_in_button_text">Sign in</string>
<!-- Text for button to go to Wifi venue information webpage when Wifi is a captive portal [CHAR LIMIT=40]-->
@@ -2290,8 +2309,14 @@
<string name="wifi_ap_choose_2G">2.4 GHz Band</string>
<!-- Label for the radio button to only choose wifi ap 5GHz band -->
<string name="wifi_ap_choose_5G">5.0 GHz Band</string>
+ <!-- Label for the radio button to only choose wifi ap 6GHz band -->
+ <string name="wifi_ap_choose_6G">6.0 GHz Band</string>
+ <!-- Label for the radio button to choose both wifi ap band (2.4GHz + 5GHz) -->
+ <string name="wifi_ap_choose_vendor_dual_band">Dual Band</string>
<!-- Label for the radio button to prefer 5GHz wifi ap band [CHAR LIMIT=80]-->
<string name="wifi_ap_prefer_5G">5.0 GHz Band preferred</string>
+ <!-- Label for the radio button to prefer 6GHz wifi ap band [CHAR LIMIT=80]-->
+ <string name="wifi_ap_prefer_6G">6.0 GHz Band preferred</string>
<!-- Label for adding to the list of selected bands when 2.4 GHz is selected -->
<string name="wifi_ap_2G">2.4 GHz</string>
<!-- Label for adding to the list of selected bands when 5.0 GHz is selected -->
@@ -2623,12 +2648,6 @@
<string name="wifi_hotspot_auto_off_title">Turn off hotspot automatically</string>
<!-- Summary for the toggle to turn off hotspot automatically [CHAR LIMIT=NONE]-->
<string name="wifi_hotspot_auto_off_summary">When no devices are connected</string>
- <!-- Title for the toggle to enable/disable the maximize compatibility [CHAR LIMIT=NONE]-->
- <string name="wifi_hotspot_maximize_compatibility">Extend compatibility</string>
- <!-- Summary for the toggle to show the maximize compatibility warning message in single AP device [CHAR LIMIT=NONE]-->
- <string name="wifi_hotspot_maximize_compatibility_single_ap_summary">Helps other devices find this hotspot. Reduces hotspot connection speed.</string>
- <!-- Summary for the toggle to show the maximize compatibility warning message in dual AP device [CHAR LIMIT=NONE]-->
- <string name="wifi_hotspot_maximize_compatibility_dual_ap_summary">Helps other devices find this hotspot. Increases battery usage.</string>
<!-- Summary text when turning hotspot on -->
<string name="wifi_tether_starting">Turning hotspot on\u2026</string>
@@ -2776,28 +2795,61 @@
<item>@*android:string/wfc_mode_cellular_preferred_summary</item>
<item>@*android:string/wfc_mode_wifi_only_summary</item>
</string-array>
+ <string-array name="wifi_calling_mode_choices_with_ims_preferred" translatable="false">
+ <item>@*android:string/wfc_mode_ims_preferred_summary</item>
+ <item>@*android:string/wfc_mode_wifi_preferred_summary</item>
+ <item>@*android:string/wfc_mode_cellular_preferred_summary</item>
+ <item>@*android:string/wfc_mode_wifi_only_summary</item>
+ </string-array>
<string-array name="wifi_calling_mode_choices_v2">
<item>Wi-Fi</item>
<item>Mobile</item>
<item>Wi-Fi only</item>
</string-array>
+ <string-array name="wifi_calling_mode_choices_v2_with_ims_preferred">
+ <item>Ims Preferred</item>
+ <item>Wi-Fi</item>
+ <item>Mobile</item>
+ <item>Wi-Fi only</item>
+ </string-array>
<string-array name="wifi_calling_mode_values" translatable="false">
<item>"2"</item>
<item>"1"</item>
<item>"0"</item>
</string-array>
+ <string-array name="wifi_calling_mode_values_with_ims_preferred" translatable="false">
+ <item>"10"</item>
+ <item>"2"</item>
+ <item>"1"</item>
+ <item>"0"</item>
+ </string-array>
<string-array name="wifi_calling_mode_choices_without_wifi_only" translatable="false">
<item>@*android:string/wfc_mode_wifi_preferred_summary</item>
<item>@*android:string/wfc_mode_cellular_preferred_summary</item>
</string-array>
+ <string-array name="wifi_calling_mode_choices_without_wifi_only_with_ims_preferred" translatable="false">
+ <item>@*android:string/wfc_mode_ims_preferred_summary</item>
+ <item>@*android:string/wfc_mode_wifi_preferred_summary</item>
+ <item>@*android:string/wfc_mode_cellular_preferred_summary</item>
+ </string-array>
<string-array name="wifi_calling_mode_choices_v2_without_wifi_only">
<item>Wi-Fi</item>
<item>Mobile</item>
</string-array>
+ <string-array name="wifi_calling_mode_choices_v2_without_wifi_only_with_ims_preferred">
+ <item>Ims Preferred</item>
+ <item>Wi-Fi</item>
+ <item>Mobile</item>
+ </string-array>
<string-array name="wifi_calling_mode_values_without_wifi_only" translatable="false">
<item>"2"</item>
<item>"1"</item>
</string-array>
+ <string-array name="wifi_calling_mode_values_without_wifi_only_with_ims_preferred" translatable="false">
+ <item>"10"</item>
+ <item>"2"</item>
+ <item>"1"</item>
+ </string-array>
<!-- Summary of WFC preference item on the WFC preference selection dialog. [CHAR LIMIT=70]-->
<string name="wifi_calling_mode_wifi_preferred_summary">If Wi\u2011Fi is unavailable, use mobile network</string>
@@ -2805,6 +2857,8 @@
<string name="wifi_calling_mode_cellular_preferred_summary">If mobile network is unavailable, use Wi\u2011Fi</string>
<!-- Summary of WFC preference item on the WFC preference selection dialog. [CHAR LIMIT=70]-->
<string name="wifi_calling_mode_wifi_only_summary">Call over Wi\u2011Fi. If Wi\u2011Fi is lost, call will end.</string>
+ <!-- Summary of WFC preference item on the WFC preference selection dialog. [CHAR LIMIT=70]-->
+ <string name="wifi_calling_mode_ims_preferred_summary">If LTE and Wi\u2011Fi are unavailabe, use 2G/3G</string>
<!-- Wi-Fi Calling settings. Text displayed when Wi-Fi Calling is off -->
<string name="wifi_calling_off_explanation">When Wi-Fi calling is on, your phone can route calls via Wi-Fi networks or your carrier\u2019s network, depending on your preference and which signal is stronger. Before turning on this feature, check with your carrier regarding fees and other details.<xliff:g id="additional_text" example="Learn More">%1$s</xliff:g></string>
@@ -8023,6 +8077,8 @@
the carrier to determine if your contacts support enhanced features, such as video calling
and RCS messaging. [CHAR LIMIT=NONE]-->
<string name="contact_discovery_opt_in_dialog_message_no_carrier_defined">Your contacts\u2019 phone numbers will be periodically sent to your carrier.<xliff:g id="empty_line" example=" ">\n\n</xliff:g>This info identifies whether your contacts can use certain features, like video calls or some messaging features.</string>
+ <!-- Enabled 5G Mode title. [CHAR LIMIT=50] -->
+ <string name="enabled_5g_mode_title">Enable 5G</string>
<!-- Preferred network type title. [CHAR LIMIT=50] -->
<string name="preferred_network_type_title">Preferred network type</string>
<!-- Preferred network type summary. [CHAR LIMIT=100] -->
@@ -8481,6 +8537,9 @@
<!-- Sound: Other sounds: Title for the option enabling touch sounds for dial pad tones. [CHAR LIMIT=30] -->
<string name="dial_pad_tones_title">Dial pad tones</string>
+ <!-- Sound: Other sounds: Title for the option enabling tones after call connected. [CHAR LIMIT=30] -->
+ <string name="call_connected_tones_title">Call connected tones</string>
+
<!-- Sound: Other sounds: Title for the option enabling touch sounds for screen locking sounds. [CHAR LIMIT=30] -->
<string name="screen_locking_sounds_title">Screen locking sound</string>
@@ -12319,6 +12378,19 @@
<!-- Part of a message for an empty state screen. A user will see this message if they try to use a certain feature, but the feature was turned off so it won't slow down their phone. [CHAR LIMIT=NONE] -->
<string name="disabled_feature_reason_slow_down_phone">This feature has been turned off because it slows down your phone</string>
+ <!-- apn names for carriers -->
+ <string name="APN_NAME_CMNET">CMNET</string>
+ <string name="APN_NAME_CMWAP">CMWAP</string>
+ <string name="APN_NAME_CMMMS">CMMMS</string>
+ <string name="APN_NAME_CUWAP">China Unicom WAP</string>
+ <string name="APN_NAME_CUNET">China Unicom NET</string>
+ <string name="APN_NAME_CUMMS">China Unicom MMS</string>
+ <string name="APN_NAME_CUSUPL">China Unicom AGPS</string>
+ <string name="APN_NAME_CTNET">CTNET</string>
+ <string name="APN_NAME_CTWAP">CTWAP</string>
+ <string name="APN_NAME_CTLTE">ctlte</string>
+ <string name="APN_NAME_CTMMS">CTWAP</string>
+
<!-- UI debug setting: preference title - show all crash dialogs [CHAR LIMIT=60] -->
<string name="show_first_crash_dialog">Always show crash dialog</string>
<!-- UI debug setting: preference summary - describes the behavior of showing a dialog every time an app crashes [CHAR LIMIT=NONE] -->
@@ -12635,6 +12707,8 @@
<!-- Text for Network mode 5g recommended [CHAR LIMIT=NONE] -->
<string name="network_5G_recommended">5G (recommended)</string>
+ <!-- Text for Network 5g lte[CHAR LIMIT=NONE] -->
+ <string name="network_5G_lte" translatable="false">5G</string>
<!-- Text for Network lte [CHAR LIMIT=NONE] -->
<string name="network_lte_pure" translatable="false">LTE</string>
<!-- Text for Network 4g [CHAR LIMIT=NONE] -->
@@ -12655,6 +12729,12 @@
<string name="network_world_mode_cdma_lte" translatable="false">LTE / CDMA</string>
<!-- Text for Network world mode GSM LTE [CHAR LIMIT=NONE] -->
<string name="network_world_mode_gsm_lte" translatable="false">LTE / GSM / UMTS</string>
+ <!-- Text for Network 3g only [CHAR LIMIT=NONE] -->
+ <string name="network_2G_3G_preferred" translatable="false">2G/3G preferred</string>
+ <!-- Text for Network 3g only [CHAR LIMIT=NONE] -->
+ <string name="network_3G_only" translatable="false">3G only</string>
+ <!-- Text for Network 2g only [CHAR LIMIT=NONE] -->
+ <string name="network_2G_only" translatable="false">2G only</string>
<!-- Available networks screen title/heading [CHAR LIMIT=NONE] -->
<string name="label_available">Available networks</string>
@@ -12689,8 +12769,17 @@
<!-- Mobile network setting screen, summary of Mobile data switch preference when the network
is unavailable, the preference selection will be disabled. [CHAR LIMIT=NONE] -->
<string name="mobile_data_settings_summary_unavailable">No SIM card available</string>
+ <!-- Mobile network setting screen, summary of Mobile data switch preference of default data
+ SUB when the call is ongoing on non-default data SUB, the preference selection will be
+ disabled. [CHAR LIMIT=NONE] -->
+ <string name="mobile_data_settings_summary_default_data_unavailable">
+ Data will automatically switch to this carrier after call ends
+ </string>
<!-- Mobile network settings screen, title of item showing the name of the default subscription
+ that will be used for data. This only appears in multi-SIM mode. [CHAR LIMIT=NONE] -->
+ <string name="data_preference">Data preference</string>
+ <!-- Mobile network settings screen, title of item showing the name of the default subscription
that will be used for calls. This only appears in multi-SIM mode. [CHAR LIMIT=NONE] -->
<string name="calls_preference">Calls preference</string>
<!-- Mobile network settings screen, title of item showing the name of the default subscription
@@ -12881,6 +12970,13 @@
<!-- Available networks screen, summary when button disallowed due to permanent automatic mode [CHAR LIMIT=NONE] -->
<string name="manual_mode_disallowed_summary">Unavailable when connected to <xliff:g id="carrier" example="verizon">%1$s</xliff:g></string>
+ <string name="select_sim_card">Select SIM card</string>
+ <string name="qtifeedback_settings_title">Hardware Feedback</string>
+ <string name="qtifeedback_settings_subtitle">Qualcomm Technologies, Inc Reporting</string>
+ <string name="qtifeedback_intent_action">com.qti.smq.snapdragonSettings</string>
+ <string name="qtifeedback_package">com.qti.smq.Feedback</string>
+ <string name="qtifeedback_activity">com.qti.smq.ui.QtiFeedbackActivity</string>
+
<!-- See more items in contextual homepage [CHAR LIMIT=30]-->
<string name="see_more">See more</string>
<!-- See less items in contextual homepage [CHAR LIMIT=30]-->
@@ -13085,6 +13181,8 @@
<!-- Summary for low storage slice. [CHAR LIMIT=NONE] -->
<string name="low_storage_summary">Storage is low. <xliff:g id="percentage" example="54%">%1$s</xliff:g> used - <xliff:g id="free_space" example="32GB">%2$s</xliff:g> free</string>
+ <string name="reset_default_apn_failed">Failed to reset default apn</string>
+
<!-- Label for button in contextual card feedback dialog for users to send feedback [CHAR LIMIT=30] -->
<string name="contextual_card_feedback_send">Send feedback</string>
<!-- String for contextual card feedback dialog [CHAR LIMIT=NONE] -->
@@ -13143,6 +13241,11 @@
<!-- Warn the user that the phone may share its location with the carrier. [CHAR LIMIT=NONE] -->
<string name="wfc_disclaimer_location_desc_text">Your carrier may collect your location when you use this service for emergency calls.\n\nVisit your carrier\u2019s privacy policy for details.</string>
+ <!-- String for about phone -->
+ <string name="ram_total_size">RAM total size</string>
+ <string name="rom_total_size">ROM total size</string>
+ <string name="software_version">Software version</string>
+ <string name="model_hardware_summary">Model&#58;%1$s; Hardware&#58;%2$s</string>
<!-- Message for forget passpoint dialog [CHAR LIMIT=none] -->
<string name="forget_passpoint_dialog_message">You may lose access to any remaining time or data. Check with your provider before removing.</string>
@@ -13303,6 +13406,19 @@
<!-- Subtext for showing the option of RTT setting. [CHAR LIMIT=NONE] -->
<string name="rtt_settings_always_visible"></string>
+ <!-- Strings for user PLMN setting. [CHAR LIMIT=NONE] -->
+ <string name="uplmn_settings_title">User Controlled PLMN</string>
+ <string name="network_id">Network ID</string>
+ <string name="dialog_network_priority_title">Priority</string>
+ <string name="uplmn_list_setting_add_plmn">New PLMN</string>
+ <string name="gsm_umts_network_preferences_title">Network Mode</string>
+ <string name="gsm_umts_network_preferences_dialogtitle">Network Mode</string>
+ <string name="voicemail_number_not_set">&lt;Not set&gt;</string>
+ <string name="reading_settings">Reading settings\u2026</string>
+ <string name="updating_settings">Updating settings\u2026</string>
+ <string name="uplmn_settings_summary">Define the preferred PLMNs in priority order</string>
+ <string name="plmn_failure_radio_off">Selecting network failure due to radio OFF or unavailable</string>
+
<!-- Button label to stop casting on media device. [CHAR LIMIT=40 -->
<string name="media_output_panel_stop_casting_button">Stop casting</string>
@@ -13636,4 +13752,14 @@
<string name="bluetooth_connect_access_dialog_negative">Don\u2019t connect</string>
<!-- Strings for Dialog connect button -->
<string name="bluetooth_connect_access_dialog_positive">Connect</string>
+ <!-- Title of selecting NR mode in developer options settings [CHAR LIMIT=NONE]-->
+ <string name="prefer_5G_nr_mode_title">Prefer 5G NR Mode</string>
+ <!-- Summary of selecting NR mode in developer options settings [CHAR LIMIT=NONE]-->
+ <string name="prefer_5G_nr_mode_summary">Enable 5G if you want to select 5G mode</string>
+ <!-- String for NSA, NSA, NSA+SA [CHAR LIMIT=NONE]-->
+ <string name="nr_nsa_sa">NSA + SA</string>
+ <string name="nr_nsa">NSA</string>
+ <string name="nr_sa">SA</string>
+ <string name="prefer_vonr_mode_title">Enable/Disable VoNR</string>
+ <string name="prefer_vonr_mode_summary">Enable or disable VoNR</string>
</resources>
diff --git a/res/values/strings_ba.xml b/res/values/strings_ba.xml
new file mode 100644
index 0000000000..0673d1efbf
--- /dev/null
+++ b/res/values/strings_ba.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="bluetooth_search_broadcasters">Search Broadcasters</string>
+ <string name="bluetooth_bcast_rcvr_device_name">Broadcast receiver</string>
+ <string name="bluetooth_source_selection_options_detail_title">
+ Configure Broadcast receiver</string>
+ <string name="bluetooth_source_selection_options_detail" product="default">Broadcast source "
+ <xliff:g id="device_name">%1$s</xliff:g> is being added to receiver.
+ (Leave Broadcast PIN blank if
+ It is Unencrypted broadcast Source)"</string>
+ <string name="bluetooth_grp_source_selection_options_detail" product="default">
+ Broadcast source "
+ <xliff:g id="device_name">%1$s</xliff:g> is being added to the connected group members.
+ (Leave Broadcast PIN blank if It is Unencrypted broadcast Source)"</string>
+ <string name="bluetooth_col_source_selection_options_detail" product="default">
+ Broadcast source "
+ <xliff:g id="device_name">%1$s</xliff:g> is being added to receiver"</string>
+ <string name="bluetooth_col_grp_source_selection_options_detail" product="default">
+ Broadcast source "
+ <xliff:g id="device_name">%1$s</xliff:g> is being added to the connected
+ group members."</string>
+ <string name="bluetooth_search_bcast_sources_pref_title">Search Broadcast
+ sources</string>
+ <string name="bluetooth_scan_source_title">Scan for Broadcast sources
+ for</string>
+ <string name="added_sources_title">Broadcast sources</string>
+ <string name="add_source_button_text">Add Broadcast Source</string>
+ <string name="update_sourceinfo_btn_txt">Update Source Info</string>
+ <string name="remove_sourceinfo_btn_txt">Remove Source Info</string>
+ <string name="source_info_details_title">Broadcast source Information</string>
+ <string name="bcast_source_info_sid">Broadcast Source Id</string>
+ <string name="bcast_source_address">Broadcast Source Device</string>
+ <string name="bcast_source_enc_status">Encryption Status</string>
+ <string name="bcast_source_metadata">Metadata</string>
+ <string name="bcast_metadata_sync_state">Metadata Sync status</string>
+ <string name="bcast_enable_metadata_sync">Metadata sync</string>
+ <string name="bcast_audio_sync_state">Audio Sync status</string>
+ <string name="bcast_enable_audio_sync">Audio sync</string>
+ <string name="bcast_update_code_title">Update Broadcast code</string>
+ <string name="bcast_update_code_summary">Add broadcast code here, and click
+ Update Broadcast Source Info</string>
+ <string name="bcast_info_update">Update Source Info</string>
+ <string name="added_sources_dashboard_title">Added Broadcast Sources</string>
+ <string name="bcast_sink_volume_title">Broadcast sink volume</string>
+ <string name="group_update_source_title">Update to all Group members?</string>
+ <string name="group_update_source_message">Do you want to Update this source
+ in all group members?</string>
+ <string name="group_remove_source_title">Remove from all Group members?</string>
+ <string name="group_remove_source_message">Do you want to remove this Broadcast source from
+ all group members?</string>
+ <string name="bluetooth_source_selection_error_message">Invalid Broadcast
+ source selected for Receiver
+ <xliff:g id="device_name">%1$s</xliff:g>.</string>
+ <string name="bluetooth_source_selection_error_src_unavail_message">selected
+ source for receiver
+ <xliff:g id="device_name">%1$s</xliff:g>. is Unavailable </string>
+ <string name="bluetooth_source_addition_error_message">Couldn\'t add the
+ Broadcast source to receiver
+ <xliff:g id="device_name">%1$s</xliff:g>.</string>
+ <string name="bluetooth_source_dup_addition_error_message">Couldn\'t add
+ the Broadcast
+ source to receiver <xliff:g id="device_name">%1$s</xliff:g>
+ . Duplicate source</string>
+ <string name="bluetooth_source_no_empty_slot_error_message">Consider removing
+ some source
+ from receiver <xliff:g id="device_name">%1$s</xliff:g>. No empty slot</string>
+ <string name="bluetooth_source_update_error_message">
+ Couldn\'t update Broadcast source
+ details of receiver <xliff:g id="device_name">%1$s</xliff:g>.</string>
+ <string name="bluetooth_source_update_invalid_group_op">
+ Couldn\'t update the Broadcast
+ Source from <xliff:g id="device_name">%1$s</xliff:g>.Invalid Group operation,
+ Try non-Group operation</string>
+ <string name="bluetooth_source_update_invalid_src_id">
+ Couldn\'t update the Broadcast Source from
+ <xliff:g id="device_name">%1$s</xliff:g>.Invalid Source Id</string>
+ <string name="bluetooth_source_setpin_error_message">
+ Couldn\'t update the Broadcast PIN code for
+ <xliff:g id="device_name">%1$s</xliff:g>.</string>
+ <string name="bluetooth_source_removal_error_message">
+ Couldn\'t remove the Broadcast Source from
+ <xliff:g id="device_name">%1$s</xliff:g>.</string>
+ <string name="bluetooth_source_remove_invalid_group_op">
+ Couldn\'t remove the Broadcast Source from
+ <xliff:g id="device_name">%1$s</xliff:g>.Invalid Group operation,
+ Try non-Group operation</string>
+ <string name="bluetooth_source_remove_invalid_src_id">
+ Couldn\'t remove the Broadcast Source from
+ <xliff:g id="device_name">%1$s</xliff:g>.Invalid Source Id</string>
+ <string name="bluetooth_source_added_message">Broadcast source added
+ successfully to receiver
+ <xliff:g id="device_name">%1$s</xliff:g>.</string>
+ <string-array name="bcast_channel_selection">
+ </string-array>
+ <string name="metadata_synced">Metadata Synced</string>
+ <string name="metadata_not_synced">Metadata not synced</string>
+ <string name="audio_synced">Audio Synced</string>
+ <string name="audio_not_synced">Audio not synced</string>
+</resources>
diff --git a/res/values/strings_group.xml b/res/values/strings_group.xml
new file mode 100644
index 0000000000..c848159604
--- /dev/null
+++ b/res/values/strings_group.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="group_id">Group ID</string>
+ <string name="refresh_group">Refresh Group</string>
+ <string name="cancel_refresh_group">Cancel Refresh</string>
+ <string name="disconnect_group">Disconnect Group</string>
+ <string name="connect_group">Connect Group</string>
+ <string name="forget_group">Forget Group</string>
+ <string name="group_previously_connected_screen_title">Previously Connected group</string>
+ <string name="group_help_url_previously_connected_devices" translatable="false"></string>
+ <string name="group_settings">Group</string>
+ <string name="previously_connected_group_screen_title">Previously Connected group</string>
+ <string name="help_url_previously_connected_group_devices" translatable="false"></string>
+ <string name="previous_connected_see_all_groups">See all groups</string>
+ <string name="group_options">Group options</string>
+ <string name="group_connected_devices">Connected Devices</string>
+ <string name="group_active_devices">Active Devices</string>
+ <string name="group_bonded_devices">Bonded Device</string>
+ <string name="group_help_url_all_connected_devices" translatable="false"></string>
+ <string name="active">Active</string>
+ <string name="groupaudio_unpair_dialog_title">Forget Group ?</string>
+ <string name="groupaudio_unpair_dialog_body">Your phone will
+ no longer be paired with group <xliff:g id="setid">%1$s</xliff:g></string>
+ <string name="groupaudio_unpair_dialog_forget_confirm_button">Forget Group</string>
+ <string name="add_source_group">Add Broadcast Source to Group</string>
+ <string name="group_apply_changes_dialog_title">Apply changes for all group members ?</string>
+ <string name="group_confirm_dialog_body">Same changes applicable for all members of group <xliff:g id="groupid">%1$s</xliff:g></string>
+ <string name="group_confirm_dialog_apply_button">Apply</string>
+</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 8402dec73c..2c7e6fcba9 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -926,4 +926,11 @@
parent="@*android:style/TextAppearance.DeviceDefault">
<item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
+
+ <style name="GroupOptionsButton" parent="android:Widget.DeviceDefault.Button">
+ <item name="android:drawablePadding">4dp</item>
+ <item name="android:layout_marginEnd">8dp</item>
+ <item name="android:paddingTop">20dp</item>
+ <item name="android:paddingBottom">20dp</item>
+ </style>
</resources>
diff --git a/res/xml/bcast_source_info_details_fragment.xml b/res/xml/bcast_source_info_details_fragment.xml
new file mode 100644
index 0000000000..5a5eef15c3
--- /dev/null
+++ b/res/xml/bcast_source_info_details_fragment.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:title="@string/source_info_details_title">
+
+ <PreferenceCategory
+ android:key="broadcast_source_details_category">
+
+ <Preference
+ android:key="broadcast_si_sourceId"
+ android:title="@string/bcast_source_info_sid"
+ android:summary="00"
+ />
+
+ <Preference
+ android:key="broadcast_si_source_address"
+ android:title="@string/bcast_source_address"
+ android:summary="00:00:00:00:00:00"
+ />
+
+ <Preference
+ android:key="broadcast_si_metadata_state"
+ android:title="@string/bcast_metadata_sync_state"
+ android:summary="NONE"
+ />
+<!--
+ <Preference
+ android:key="broadcast_si_audio_state"
+ android:title="@string/bcast_audio_sync_state"
+ android:summary="NONE"
+ />
+-->
+
+ <MultiSelectListPreference
+ android:title="@string/bcast_audio_sync_state"
+ android:key="broadcast_si_audio_state"
+ android:persistent="false"
+ android:entries="@array/bcast_channel_selection"
+ android:entryValues="@array/bcast_channel_selection"
+ style="@style/SettingsMultiSelectListPreference"
+ />
+
+ <Preference
+ android:key="broadcast_si_encryption_state"
+ android:title="@string/bcast_source_enc_status"
+ android:summary="No encryption key"
+ />
+
+ <Preference
+ android:key="broadcast_si_metadata"
+ android:title="@string/bcast_source_metadata"
+ android:summary="Music"
+ />
+<!--
+ <SwitchPreference
+ android:key="broadcast_si_enable_metadata_sync"
+ android:title="@string/bcast_enable_metadata_sync"
+ android:defaultValue="false"
+ settings:allowDividerAbove="true"/>
+-->
+ <SwitchPreference
+ android:key="broadcast_si_enable_audio_sync"
+ android:title="@string/bcast_enable_audio_sync"
+ android:defaultValue="false" />
+
+ <EditTextPreference
+ android:key="update_broadcast_code"
+ android:title="@string/bcast_update_code_title"
+ android:summary="@string/bcast_update_code_summary"
+ android:inputType="text"
+ android:ems="16"
+ android:defaultValue="" />
+
+ <com.android.settingslib.widget.ActionButtonsPreference
+ android:key="bcast_si_update_button"
+ android:title="@string/bcast_info_update"
+ settings:allowDividerBelow="true"/>
+
+ </PreferenceCategory>
+ </PreferenceScreen>
diff --git a/res/xml/bluetooth_broadcast_pin_config.xml b/res/xml/bluetooth_broadcast_pin_config.xml
new file mode 100644
index 0000000000..56a89600c5
--- /dev/null
+++ b/res/xml/bluetooth_broadcast_pin_config.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2021, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<ScrollView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:padding="8dp">
+ <TextView
+ android:id="@+id/bluetooth_broadcast_current_pin"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+ <RadioGroup
+ android:id="@+id/bluetooth_broadcast_pin_config_radio_group"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <include
+ android:id="@+id/bluetooth_broadcast_pin_unencrypted"
+ layout="@layout/preference_widget_dialog_radiobutton"/>
+
+ <include
+ android:id="@+id/bluetooth_broadcast_pin_4"
+ layout="@layout/preference_widget_dialog_radiobutton"/>
+
+ <include
+ android:id="@+id/bluetooth_broadcast_pin_16"
+ layout="@layout/preference_widget_dialog_radiobutton"/>
+
+ </RadioGroup>
+
+ </LinearLayout>
+
+</ScrollView>
diff --git a/res/xml/bluetooth_device_details_fragment.xml b/res/xml/bluetooth_device_details_fragment.xml
index 9df195584d..7ee1524010 100644
--- a/res/xml/bluetooth_device_details_fragment.xml
+++ b/res/xml/bluetooth_device_details_fragment.xml
@@ -61,4 +61,20 @@
settings:searchable="false"
settings:controller="com.android.settings.bluetooth.BluetoothDetailsMacAddressController"/>
-</PreferenceScreen> \ No newline at end of file
+ <com.android.settingslib.widget.ActionButtonsPreference
+ android:key="sync_helper_buttons"
+ settings:allowDividerBelow="true"/>
+ <PreferenceCategory
+ android:key="added_sources"
+ android:title="@string/added_sources_dashboard_title">
+ </PreferenceCategory>
+
+ <com.android.settings.bluetooth.BADeviceVolumePreference
+ android:key="ba_device_volume"
+ android:icon="@drawable/ic_volume_media_bt"
+ android:title="@string/bcast_sink_volume_title"
+ settings:allowDividerBelow="true"
+ settings:allowDividerAbove="true"
+ settings:controller="com.android.settings.bluetooth.BADeviceVolumeController"/>
+
+</PreferenceScreen>
diff --git a/res/xml/bluetooth_group_details_fragment.xml b/res/xml/bluetooth_group_details_fragment.xml
new file mode 100644
index 0000000000..47e7dc442d
--- /dev/null
+++ b/res/xml/bluetooth_group_details_fragment.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+-->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:title="@string/group_options">
+ <com.android.settings.widget.GroupOptionsPreference
+ android:key="group_options" />
+ <PreferenceCategory
+ android:key="group_options_active_devices"
+ android:title="@string/group_active_devices" />
+ <PreferenceCategory
+ android:key="group_options_connected_devices"
+ android:title="@string/group_connected_devices" />
+ <PreferenceCategory
+ android:key="group_options_bonded_devices"
+ android:title="@string/group_bonded_devices" />
+</PreferenceScreen> \ No newline at end of file
diff --git a/res/xml/bluetooth_screen.xml b/res/xml/bluetooth_screen.xml
index 86dc8a12c7..14f845fc22 100644
--- a/res/xml/bluetooth_screen.xml
+++ b/res/xml/bluetooth_screen.xml
@@ -24,6 +24,16 @@
android:summary="@string/summary_placeholder"
settings:controller="com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController"/>
+ <com.android.settingslib.RestrictedSwitchPreference
+ android:key="bluetooth_screen_broadcast_enable"
+ android:title="@string/bluetooth_broadcast"
+ android:summary="@string/summary_placeholder"/>
+
+ <com.android.settingslib.RestrictedPreference
+ android:key="bluetooth_screen_broadcast_pin_configure"
+ android:title="@string/bluetooth_broadcast_pin_configure"
+ android:summary="@string/summary_placeholder"/>
+
<com.android.settingslib.RestrictedPreference
android:key="bluetooth_screen_add_bt_devices"
android:title="@string/bluetooth_pairing_pref_title"
diff --git a/res/xml/bluetooth_search_bcast_sources.xml b/res/xml/bluetooth_search_bcast_sources.xml
new file mode 100644
index 0000000000..482af5a40e
--- /dev/null
+++ b/res/xml/bluetooth_search_bcast_sources.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:key="bluetooth_search_bcast_sources_detail_screen"
+ android:title="@string/bluetooth_search_bcast_sources_pref_title">
+
+ <Preference
+ android:key="bt_bcast_rcvr_device"
+ android:title="@string/bluetooth_bcast_rcvr_device_name"
+ android:summary="@string/summary_placeholder"
+ />
+
+ <com.android.settings.bluetooth.BluetoothProgressCategory
+ android:key="available_audio_sources"
+ android:title="@string/bluetooth_paired_device_title"/>
+
+ <com.android.settingslib.widget.FooterPreference/>
+</PreferenceScreen>
+
diff --git a/res/xml/connected_devices.xml b/res/xml/connected_devices.xml
index 8e606484b7..6291547e22 100644
--- a/res/xml/connected_devices.xml
+++ b/res/xml/connected_devices.xml
@@ -36,6 +36,11 @@
android:title="@string/connected_device_other_device_title"
settings:controller="com.android.settings.connecteddevice.ConnectedDeviceGroupController"/>
+ <PreferenceCategory
+ android:key="saved_tws_device_list"
+ android:title="@string/connected_tws_device_saved_title"
+ settings:controller="com.android.settings.connecteddevice.SavedTwsDeviceGroupController"/>
+
<com.android.settingslib.RestrictedPreference
android:key="add_bt_devices"
android:title="@string/bluetooth_pairing_pref_title"
@@ -48,6 +53,71 @@
settings:controller="com.android.settings.connecteddevice.AddDevicePreferenceController"/>
<PreferenceCategory
+ android:key="group_connected_device_list"
+ settings:controller="com.android.settings.connecteddevice.GroupConnectedBluetoothDevicesController"
+ android:layout="@layout/preference_category_no_label"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="group_one"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="group_two"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="group_three"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="group_four"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="group_five"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="group_six"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="group_seven"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="group_eight"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="group_nine"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="group_remaining"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <PreferenceCategory
android:key="previously_connected_devices"
android:title="@string/connected_device_previously_connected_title"
settings:controller="com.android.settings.connecteddevice.PreviouslyConnectedDevicePreferenceController">
@@ -61,6 +131,20 @@
android:fragment="com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment"/>
</PreferenceCategory>
+ <PreferenceCategory
+ android:key="group_previously_connected_devices"
+ android:title="@string/group_previously_connected_screen_title"
+ settings:controller="com.android.settings.connecteddevice.GroupPreviouslyConnectedDevicePreferenceController">
+
+ <Preference
+ android:key="group_previously_connected_devices_see_all"
+ android:title="@string/previous_connected_see_all"
+ android:icon="@drawable/ic_chevron_right_24dp"
+ android:order="100"
+ settings:searchable="false"
+ android:fragment="com.android.settings.connecteddevice.GroupPreviouslyConnectedDeviceDashboardFragment"/>
+ </PreferenceCategory>
+
<Preference
android:key="connection_preferences"
android:title="@string/connected_device_connections_title"
diff --git a/res/xml/developer_mobile_network_list.xml b/res/xml/developer_mobile_network_list.xml
new file mode 100644
index 0000000000..c966f73e40
--- /dev/null
+++ b/res/xml/developer_mobile_network_list.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2020, The Linux Foundation. All rights reserved
+ Not a contribution
+
+ Copyright (C) 2019 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:title="@string/network_settings_title">
+
+ <com.android.settingslib.RestrictedPreference
+ android:key="prefer_5g_add_more"
+ settings:isPreferenceVisible="false"
+ settings:userRestriction="no_config_mobile_networks"
+ settings:useAdminDisabledSummary="true"
+ settings:searchable="false"
+ android:title="@string/mobile_network_list_add_more"
+ android:icon="@drawable/ic_menu_add_activated_tint"
+ android:order="100" >
+ <intent android:action="android.telephony.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION">
+ <extra android:name="android.telephony.euicc.extra.FORCE_PROVISION"
+ android:value="true"/>
+ </intent>
+ </com.android.settingslib.RestrictedPreference>
+
+</PreferenceScreen>
diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml
index e389747bf6..34ce000c53 100644
--- a/res/xml/development_settings.xml
+++ b/res/xml/development_settings.xml
@@ -263,12 +263,28 @@
android:title="@string/debug_networking_category"
android:order="400">
+ <com.android.settings.widget.AddPreference
+ android:key="prefer_5G_nr_mode"
+ android:title="@string/prefer_5G_nr_mode_title"
+ settings:controller="com.android.settings.development.Prefer5GNetworkSummaryController"/>
+
+ <com.android.settingslib.RestrictedPreference
+ android:fragment="com.android.settings.development.PreferVonrSettings"
+ android:key="prefer_vonr_mode"
+ android:title="@string/prefer_vonr_mode_title"
+ android:summary="@string/prefer_vonr_mode_summary"/>
+
<SwitchPreference
android:key="wifi_display_certification"
android:title="@string/wifi_display_certification"
android:summary="@string/wifi_display_certification_summary" />
<SwitchPreference
+ android:key="wifi_coverage_extend"
+ android:title="@string/wifi_coverage_extend"
+ android:summary="@string/wifi_coverage_extend_summary" />
+
+ <SwitchPreference
android:key="wifi_verbose_logging"
android:title="@string/wifi_verbose_logging"
android:summary="@string/wifi_verbose_logging_summary" />
@@ -289,6 +305,12 @@
android:summary="@string/mobile_data_always_on_summary" />
<SwitchPreference
+ android:key="smart_dds_switch"
+ android:title="@string/smart_dds_switch"
+ android:summary="@string/smart_dds_switch_summary"
+ android:enabled="false" />
+
+ <SwitchPreference
android:key="tethering_hardware_offload"
android:title="@string/tethering_hardware_offload"
android:summary="@string/tethering_hardware_offload_summary" />
diff --git a/res/xml/location_settings.xml b/res/xml/location_settings.xml
index fe87efd73d..15128dd913 100644..100755
--- a/res/xml/location_settings.xml
+++ b/res/xml/location_settings.xml
@@ -35,6 +35,13 @@
settings:controller="com.android.settings.location.RecentLocationAccessSeeAllButtonPreferenceController"
settings:searchable="false"/>
+ <CheckBoxPreference
+ android:key="assisted_gps"
+ android:title="@string/assisted_gps"
+ android:summaryOn="@string/assisted_gps_enabled"
+ android:summaryOff="@string/assisted_gps_disabled"
+ settings:controller="com.android.settings.location.AgpsPreferenceController"/>
+
<PreferenceCategory
android:key="location_advanced_settings"
android:layout="@layout/preference_category_no_label">
diff --git a/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml
index 673994a9a9..8e8b350b69 100644..100755
--- a/res/xml/mobile_network_settings.xml
+++ b/res/xml/mobile_network_settings.xml
@@ -34,10 +34,15 @@
android:selectable="false"/>
<ListPreference
+ android:key="data_preference"
+ android:title="@string/data_preference"
+ settings:controller="com.android.settings.network.telephony.DataDefaultSubscriptionController"
+ settings:allowDividerAbove="true"/>
+
+ <ListPreference
android:key="calls_preference"
android:title="@string/calls_preference"
- settings:controller="com.android.settings.network.telephony.CallsDefaultSubscriptionController"
- settings:allowDividerAbove="true"/>
+ settings:controller="com.android.settings.network.telephony.CallsDefaultSubscriptionController"/>
<ListPreference
android:key="sms_preference"
@@ -116,7 +121,6 @@
android:summary="@string/enhanced_4g_lte_mode_summary_4g_calling"
settings:keywords="@string/keywords_enhance_4g_lte"
settings:controller="com.android.settings.network.telephony.Enhanced4gCallingPreferenceController"/>
-
<SwitchPreference
android:key="advance_call"
android:title="@string/enhanced_4g_lte_mode_title_advanced_calling"
@@ -124,6 +128,11 @@
android:summary="@string/enhanced_4g_lte_mode_summary"
settings:keywords="@string/keywords_enhance_4g_lte"
settings:controller="com.android.settings.network.telephony.Enhanced4gAdvancedCallingPreferenceController"/>
+ <SwitchPreference
+ android:key="enabled_5g"
+ android:title="@string/enabled_5g_mode_title"
+ android:persistent="true"
+ settings:controller="com.android.settings.network.telephony.Enabled5GPreferenceController"/>
<SwitchPreference
android:key="contact_discovery_opt_in"
@@ -235,6 +244,15 @@
settings:controller="com.android.settings.network.telephony.ApnPreferenceController"/>
<Preference
+ android:key="uplmn_settings_key"
+ android:persistent="false"
+ android:title="@string/uplmn_settings_title"
+ android:summary="@string/uplmn_settings_summary"
+ settings:allowDividerAbove="true"
+ settings:controller="com.android.settings.network.telephony.UserPLMNPreferenceController">
+ </Preference>
+
+ <Preference
android:key="carrier_settings_key"
android:title="@string/carrier_settings_title"
settings:controller="com.android.settings.network.telephony.CarrierPreferenceController">
diff --git a/res/xml/my_device_info.xml b/res/xml/my_device_info.xml
index 9547318a86..5c18af0510 100644
--- a/res/xml/my_device_info.xml
+++ b/res/xml/my_device_info.xml
@@ -211,4 +211,22 @@
settings:controller="com.android.settings.deviceinfo.BuildNumberPreferenceController"/>
</PreferenceCategory>
+ <!-- Software version -->
+ <Preference
+ android:key="software_version"
+ android:order="44"
+ android:title="@string/software_version"
+ android:summary="@string/summary_placeholder"
+ android:selectable="false"
+ settings:enableCopying="true"/>
+
+ <!-- Storage size, including two items: ROM and RAM total size -->
+ <Preference
+ android:key="key_storage_total_size"
+ android:order="45"
+ android:title="@string/ram_total_size"
+ android:summary="@string/summary_placeholder"
+ android:selectable="false"
+ settings:allowDividerAbove="true"
+ settings:enableCopying="true"/>
</PreferenceScreen>
diff --git a/res/xml/other_sound_settings.xml b/res/xml/other_sound_settings.xml
index 7b3f362eec..d0ddc2257e 100644
--- a/res/xml/other_sound_settings.xml
+++ b/res/xml/other_sound_settings.xml
@@ -24,6 +24,11 @@
android:key="dial_pad_tones"
android:title="@string/dial_pad_tones_title" />
+ <!-- Call connected tones -->
+ <SwitchPreference
+ android:key="call_connected_tones"
+ android:title="@string/call_connected_tones_title" />
+
<!-- Screen locking sounds -->
<SwitchPreference
android:key="screen_locking_sounds"
diff --git a/res/xml/prefer_vonr_list.xml b/res/xml/prefer_vonr_list.xml
new file mode 100644
index 0000000000..7fab44784c
--- /dev/null
+++ b/res/xml/prefer_vonr_list.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 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"
+ android:title="@string/prefer_vonr_mode_title">
+</PreferenceScreen>
diff --git a/res/xml/previously_connected_group_devices.xml b/res/xml/previously_connected_group_devices.xml
new file mode 100644
index 0000000000..c45d9ff6e1
--- /dev/null
+++ b/res/xml/previously_connected_group_devices.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<PreferenceScreen
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:title="@string/group_previously_connected_screen_title">
+ <PreferenceCategory
+ android:key="group_saved_device_list"
+ settings:controller="com.android.settings.connecteddevice.GroupSavedDeviceController"/>
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="pcg_one"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="pcg_two"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="pcg_three"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="pcg_four"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="pcg_five"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="pcg_six"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="pcg_seven"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="pcg_eight"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="pcg_nine"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+
+ <com.android.settings.widget.GroupPreferenceCategory
+ android:key="pcg_remaining"
+ android:layout="@layout/preference_category_no_label"
+ settings:allowDividerAbove="true"
+ settings:allowDividerBelow="true"/>
+</PreferenceScreen>
diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml
index e30f13915b..1010a294e9 100644
--- a/res/xml/sound_settings.xml
+++ b/res/xml/sound_settings.xml
@@ -218,6 +218,12 @@
android:title="@string/emergency_tone_title"
android:summary="%s"
android:order="-10"/>
+ <!-- Call connected tones -->
+
+ <SwitchPreference
+ android:key="call_connected_tones"
+ android:title="@string/call_connected_tones_title" />
+
<Preference
android:key="sound_work_settings"
diff --git a/res/xml/uplmn_editor.xml b/res/xml/uplmn_editor.xml
new file mode 100755
index 0000000000..30199d15db
--- /dev/null
+++ b/res/xml/uplmn_editor.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res/com.android.settings"
+ android:title="@string/uplmn_settings_title">
+ <Preference
+ android:title="@string/network_id"
+ android:key="network_id_key" />
+ <EditTextPreference
+ android:title="@string/dialog_network_priority_title"
+ android:dialogTitle="@string/dialog_network_priority_title"
+ android:key="priority_key"
+ android:singleLine="true"
+ android:inputType="number" />
+ <ListPreference
+ android:title="@string/gsm_umts_network_preferences_title"
+ android:dialogTitle="@string/gsm_umts_network_preferences_dialogtitle"
+ android:key="network_mode_key"
+ android:entries="@array/uplmn_prefer_network_mode_td_choices"
+ android:entryValues="@array/uplmn_prefer_network_mode_values" />
+</PreferenceScreen>
diff --git a/res/xml/uplmn_settings.xml b/res/xml/uplmn_settings.xml
new file mode 100755
index 0000000000..dfca65547c
--- /dev/null
+++ b/res/xml/uplmn_settings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (c) 2020, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:title="@string/uplmn_settings_title"
+ android:key="button_uplmn_list_key"
+ android:persistent="false">
+</PreferenceScreen>
diff --git a/res/xml/wifi_tether_settings.xml b/res/xml/wifi_tether_settings.xml
index 21f347bb02..34d8032cbb 100644
--- a/res/xml/wifi_tether_settings.xml
+++ b/res/xml/wifi_tether_settings.xml
@@ -37,12 +37,12 @@
android:persistent="false"
android:title="@string/wifi_hotspot_password_title"/>
+ <ListPreference
+ android:key="wifi_tether_network_ap_band"
+ android:title="@string/wifi_hotspot_ap_band_title"/>
+
<SwitchPreference
android:key="wifi_tether_auto_turn_off"
android:title="@string/wifi_hotspot_auto_off_title"
android:summary="@string/wifi_hotspot_auto_off_summary"/>
-
- <SwitchPreference
- android:key="wifi_tether_maximize_compatibility"
- android:title="@string/wifi_hotspot_maximize_compatibility"/>
</PreferenceScreen>
diff --git a/src/com/android/settings/AirplaneModeEnabler.java b/src/com/android/settings/AirplaneModeEnabler.java
index 735ae23e78..738c960379 100644
--- a/src/com/android/settings/AirplaneModeEnabler.java
+++ b/src/com/android/settings/AirplaneModeEnabler.java
@@ -20,6 +20,7 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.os.Looper;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
@@ -140,6 +141,10 @@ public class AirplaneModeEnabler extends GlobalSettingsChangeListener {
}
}
+ public boolean isInScbm() {
+ return SystemProperties.getBoolean("ril.inscbm", false);
+ }
+
/**
* Check the status of ECM mode
*
@@ -167,9 +172,9 @@ public class AirplaneModeEnabler extends GlobalSettingsChangeListener {
}
public void setAirplaneMode(boolean isAirplaneModeOn) {
- if (isInEcmMode()) {
- // In ECM mode, do not update database at this point
- Log.d(LOG_TAG, "ECM airplane mode=" + isAirplaneModeOn);
+ if (isInEcmMode() || isInScbm()) {
+ // In Emergency mode, do not update database at this point
+ Log.d(LOG_TAG, "Emergency mode airplane mode=" + isAirplaneModeOn);
} else {
mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_AIRPLANE_TOGGLE,
isAirplaneModeOn);
@@ -177,9 +182,11 @@ public class AirplaneModeEnabler extends GlobalSettingsChangeListener {
}
}
- public void setAirplaneModeInECM(boolean isECMExit, boolean isAirplaneModeOn) {
- Log.d(LOG_TAG, "Exist ECM=" + isECMExit + ", with airplane mode=" + isAirplaneModeOn);
- if (isECMExit) {
+ public void setAirplaneModeInEmergencyMode(boolean isEmergencyModeExit,
+ boolean isAirplaneModeOn) {
+ Log.d(LOG_TAG, "Exist Emergency Mode=" + isEmergencyModeExit +
+ ", with airplane mode=" + isAirplaneModeOn);
+ if (isEmergencyModeExit) {
// update database based on the current checkbox state
setAirplaneModeOn(isAirplaneModeOn);
} else {
diff --git a/src/com/android/settings/DBReadAsyncTask.java b/src/com/android/settings/DBReadAsyncTask.java
new file mode 100644
index 0000000000..6cb5429f8e
--- /dev/null
+++ b/src/com/android/settings/DBReadAsyncTask.java
@@ -0,0 +1,108 @@
+/*
+Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.AsyncTask;
+
+public class DBReadAsyncTask extends AsyncTask<Void, Void, Boolean> {
+
+ /**
+ * SMQ preferences key.
+ */
+ public static final String SMQ_KEY_VALUE = "app_status";
+
+ /**
+ * The authority of the provider.
+ */
+ public static final String AUTHORITY = "com.qti.smq.Feedback.provider";
+ /**
+ * The content URI.
+ */
+ final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
+ /**
+ * The Content URI for this table.
+ */
+ final Uri SNAP_CONTENT_URI = Uri.withAppendedPath(
+ CONTENT_URI, "smq_settings");
+
+ Context mContext;
+
+ public static final String KEY_VALUE = "app_status";
+
+ public DBReadAsyncTask(Context mContext) {
+ super();
+ this.mContext = mContext;
+ }
+
+ @Override
+ protected Boolean doInBackground(final Void... params) {
+ final String whereClause = "key" + "=?";
+ final String[] selectionArgs = { KEY_VALUE };
+
+ final Cursor c = mContext.getContentResolver().query(
+ SNAP_CONTENT_URI, null, whereClause,
+ selectionArgs, null);
+ final SharedPreferences sharedPreferences = mContext
+ .getSharedPreferences(SmqSettings.SMQ_PREFS_NAME, Context.MODE_PRIVATE);
+
+ if (c!= null && c.getCount() > 0) {
+ c.moveToFirst();
+ final int value = c.getInt(1);
+
+ final int appStatus = sharedPreferences.getInt(KEY_VALUE, 0);
+ if (appStatus == value) {
+ // Do nothing
+ } else {
+ //Save preference and notify.
+ final SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.putInt(KEY_VALUE, value);
+ editor.commit();
+
+ }
+
+ }
+ else{
+ //No such table. don't show menu.
+ final SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.putInt(KEY_VALUE, 0);
+ editor.commit();
+ }
+ if(c != null){
+ c.close();
+ }
+
+ return true;
+ }
+
+} \ No newline at end of file
diff --git a/src/com/android/settings/IccLockSettings.java b/src/com/android/settings/IccLockSettings.java
index e89e84b9df..2b8dcba38c 100644
--- a/src/com/android/settings/IccLockSettings.java
+++ b/src/com/android/settings/IccLockSettings.java
@@ -133,6 +133,7 @@ public class IccLockSettings extends SettingsPreferenceFragment
private int mSlotId = -1;
private int mSubId;
private TelephonyManager mTelephonyManager;
+ private SubscriptionManager mSubscriptionManager;
// For replies from IccCard interface
private Handler mHandler = new Handler() {
@@ -185,6 +186,7 @@ public class IccLockSettings extends SettingsPreferenceFragment
mProxySubscriptionMgr.setLifecycle(getLifecycle());
mTelephonyManager = getContext().getSystemService(TelephonyManager.class);
+ mSubscriptionManager = getContext().getSystemService(SubscriptionManager.class);
addPreferencesFromResource(R.xml.sim_lock_settings);
@@ -276,7 +278,11 @@ public class IccLockSettings extends SettingsPreferenceFragment
for (int i = 0; i < numSims; ++i) {
final SubscriptionInfo subInfo = getVisibleSubscriptionInfoForSimSlotIndex(i);
if (subInfo != null) {
- componenterList.add(subInfo);
+ final int slot = subInfo.getSimSlotIndex();
+ if (mSubscriptionManager.getSimStateForSlotIndex(slot) !=
+ TelephonyManager.SIM_STATE_NOT_READY) {
+ componenterList.add(subInfo);
+ }
}
}
@@ -334,6 +340,11 @@ public class IccLockSettings extends SettingsPreferenceFragment
final SubscriptionInfo sir = getVisibleSubscriptionInfoForSimSlotIndex(mSlotId);
final int subId = (sir != null) ? sir.getSubscriptionId()
: SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
+
+ int cardState = mTelephonyManager.getSimState();
+ boolean canInteract = cardState == TelephonyManager.SIM_STATE_READY ||
+ cardState == TelephonyManager.SIM_STATE_LOADED;
if (mSubId != subId) {
mSubId = subId;
@@ -344,10 +355,10 @@ public class IccLockSettings extends SettingsPreferenceFragment
}
if (mPinDialog != null) {
- mPinDialog.setEnabled(sir != null);
+ mPinDialog.setEnabled(sir != null && canInteract);
}
if (mPinToggle != null) {
- mPinToggle.setEnabled(sir != null);
+ mPinToggle.setEnabled(sir != null && canInteract);
if (sir != null) {
mPinToggle.setChecked(isIccLockEnabled());
diff --git a/src/com/android/settings/ResetNetworkConfirm.java b/src/com/android/settings/ResetNetworkConfirm.java
index f79bdb2e36..14eabf66fa 100644
--- a/src/com/android/settings/ResetNetworkConfirm.java
+++ b/src/com/android/settings/ResetNetworkConfirm.java
@@ -19,6 +19,7 @@ package com.android.settings;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.app.Activity;
+import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothAdapter;
@@ -49,12 +50,13 @@ import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.VisibleForTesting;
-import androidx.appcompat.app.AlertDialog;
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.enterprise.ActionDisabledByAdminDialogHelper;
import com.android.settings.network.apn.ApnSettings;
import com.android.settingslib.RestrictedLockUtilsInternal;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
/**
* Confirm and execute a reset of the network settings to a clean "just out of the box"
@@ -139,6 +141,13 @@ public class ResetNetworkConfirm extends InstrumentedFragment {
BluetoothAdapter btAdapter = btManager.getAdapter();
if (btAdapter != null) {
btAdapter.factoryReset();
+ LocalBluetoothManager mLocalBtManager =
+ LocalBluetoothManager.getInstance(mContext, null);
+ if (mLocalBtManager != null) {
+ CachedBluetoothDeviceManager cachedDeviceManager =
+ mLocalBtManager.getCachedDeviceManager();
+ cachedDeviceManager.clearAllDevices();
+ }
}
}
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index 7154081841..cc8d87dcb1 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -314,6 +314,8 @@ public class Settings extends SettingsActivity {
public static class StorageDashboardActivity extends SettingsActivity {}
public static class AccountDashboardActivity extends SettingsActivity {}
public static class SystemDashboardActivity extends SettingsActivity {}
+ public static class SupportDashboardActivity extends SettingsActivity {}
+ public static class SMQQtiFeedbackActivity extends SettingsActivity { /* empty */ }
/**
* Activity for MediaControlsSettings
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index d3d3604a2c..7941562872 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -80,7 +80,6 @@ import com.google.android.setupcompat.util.WizardManagerHelper;
import java.util.ArrayList;
import java.util.List;
-
public class SettingsActivity extends SettingsBaseActivity
implements PreferenceManager.OnPreferenceTreeClickListener,
PreferenceFragmentCompat.OnPreferenceStartFragmentCallback,
@@ -171,6 +170,7 @@ public class SettingsActivity extends SettingsBaseActivity
private CharSequence mInitialTitle;
private int mInitialTitleResId;
+ private SmqSettings mSMQ;
private BroadcastReceiver mDevelopmentSettingsListener;
@@ -270,6 +270,8 @@ public class SettingsActivity extends SettingsBaseActivity
getWindow().setUiOptions(intent.getIntExtra(EXTRA_UI_OPTIONS, 0));
}
+ mSMQ = new SmqSettings(getApplicationContext());
+
// Getting Intent properties can only be done after the super.onCreate(...)
final String initialFragmentName = getInitialFragmentName(intent);
@@ -691,7 +693,16 @@ public class SettingsActivity extends SettingsBaseActivity
*/
private void switchToFragment(String fragmentName, Bundle args, boolean validate,
int titleResId, CharSequence title) {
+ if (fragmentName.equals(getString(R.string.qtifeedback_intent_action))){
+ final Intent newIntent = new Intent(getString(R.string.qtifeedback_intent_action));
+ newIntent.addCategory("android.intent.category.DEFAULT");
+ startActivity(newIntent);
+ finish();
+ return;
+ }
+
Log.d(LOG_TAG, "Switching to fragment " + fragmentName);
+
if (validate && !isValidFragment(fragmentName)) {
throw new IllegalArgumentException("Invalid fragment for this activity: "
+ fragmentName);
@@ -735,6 +746,10 @@ public class SettingsActivity extends SettingsBaseActivity
pm.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH), isAdmin)
|| somethingChanged;
+ if(mSMQ.isShowSmqSettings()){
+ somethingChanged = setTileEnabled(changedList, new ComponentName(packageName, Settings.SMQQtiFeedbackActivity.class.getName()), mSMQ.isShowSmqSettings(), isAdmin) || somethingChanged;
+ }
+
// Enable DataUsageSummaryActivity if the data plan feature flag is turned on otherwise
// enable DataPlanUsageSummaryActivity.
somethingChanged = setTileEnabled(changedList,
@@ -749,7 +764,7 @@ public class SettingsActivity extends SettingsBaseActivity
isAdmin) || somethingChanged;
somethingChanged = setTileEnabled(changedList, new ComponentName(packageName,
- Settings.PowerUsageSummaryActivity.class.getName()),
+ Settings.PowerUsageSummaryActivity.class.getName()),
mBatteryPresent, isAdmin) || somethingChanged;
somethingChanged = setTileEnabled(changedList, new ComponentName(packageName,
diff --git a/src/com/android/settings/SmqSettings.java b/src/com/android/settings/SmqSettings.java
new file mode 100644
index 0000000000..65f87039fb
--- /dev/null
+++ b/src/com/android/settings/SmqSettings.java
@@ -0,0 +1,65 @@
+/*
+Copyright (c) 2017, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+public class SmqSettings {
+
+ /**
+ * The application context.
+ */
+ private Context mContext;
+ private SharedPreferences mSmqPreferences;
+
+ /**
+ * SMQ preferences key.
+ */
+ public static final String SMQ_KEY_VALUE = "app_status";
+
+ /**
+ * Shared preferences name.
+ */
+ public static final String SMQ_PREFS_NAME = "smqpreferences";
+
+ public SmqSettings(final Context context) {
+ mContext = context;
+ new DBReadAsyncTask(mContext).execute();
+ mSmqPreferences = mContext.getSharedPreferences(
+ SMQ_PREFS_NAME, Context.MODE_PRIVATE);
+ }
+
+ public boolean isShowSmqSettings() {
+ final int iShowSmq = mSmqPreferences.getInt(SMQ_KEY_VALUE, 0);
+ final boolean showSmq = iShowSmq > 0 ? true : false;
+ return showSmq;
+ }
+
+}
diff --git a/src/com/android/settings/TestingSettingsBroadcastReceiver.java b/src/com/android/settings/TestingSettingsBroadcastReceiver.java
index 30a0d796c1..3f7bce5447 100644
--- a/src/com/android/settings/TestingSettingsBroadcastReceiver.java
+++ b/src/com/android/settings/TestingSettingsBroadcastReceiver.java
@@ -35,7 +35,7 @@ public class TestingSettingsBroadcastReceiver extends BroadcastReceiver {
&& intent.getAction().equals(TelephonyManager.ACTION_SECRET_CODE)) {
Intent i = new Intent(Intent.ACTION_MAIN);
i.setClass(context, TestingSettingsActivity.class);
- i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(i);
}
}
diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java
index 1a21b5582a..16b68ccfdc 100644..100755
--- a/src/com/android/settings/TetherSettings.java
+++ b/src/com/android/settings/TetherSettings.java
@@ -162,7 +162,7 @@ public class TetherSettings extends RestrictedSettingsFragment
final Activity activity = getActivity();
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- if (adapter != null) {
+ if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) {
adapter.getProfileProxy(activity.getApplicationContext(), mProfileServiceListener,
BluetoothProfile.PAN);
}
@@ -285,12 +285,20 @@ public class TetherSettings extends RestrictedSettingsFragment
updateBluetoothAndEthernetState();
updateUsbPreference();
} else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+ int status = intent
+ .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
if (mBluetoothEnableForTether) {
- switch (intent
- .getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)) {
+ switch (status) {
case BluetoothAdapter.STATE_ON:
startTethering(TETHERING_BLUETOOTH);
mBluetoothEnableForTether = false;
+ if (mBluetoothPan.get() == null) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ adapter.getProfileProxy(getActivity().getApplicationContext(),
+ mProfileServiceListener, BluetoothProfile.PAN);
+ }
+ }
break;
case BluetoothAdapter.STATE_OFF:
@@ -301,6 +309,18 @@ public class TetherSettings extends RestrictedSettingsFragment
default:
// ignore transition states
}
+ } else {
+ switch (status) {
+ case BluetoothAdapter.STATE_ON:
+ if (mBluetoothPan.get() == null) {
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null) {
+ adapter.getProfileProxy(getActivity().getApplicationContext(),
+ mProfileServiceListener, BluetoothProfile.PAN);
+ }
+ }
+ break;
+ }
}
updateBluetoothAndEthernetState();
} else if (action.equals(BluetoothPan.ACTION_TETHERING_STATE_CHANGED)) {
diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java
index 50f6003ce5..d2f7c21245 100644
--- a/src/com/android/settings/Utils.java
+++ b/src/com/android/settings/Utils.java
@@ -45,6 +45,7 @@ import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.content.res.Resources.NotFoundException;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -70,6 +71,7 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.os.SystemProperties;
import android.os.storage.VolumeInfo;
import android.preference.PreferenceFrameLayout;
import android.provider.ContactsContract.CommonDataKinds;
@@ -77,6 +79,9 @@ import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Profile;
import android.provider.ContactsContract.RawContacts;
+import android.provider.Settings;
+import android.provider.Telephony;
+import android.service.persistentdata.PersistentDataBlockManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.Spannable;
@@ -119,6 +124,8 @@ import java.util.Iterator;
import java.util.List;
import java.util.Locale;
+import org.codeaurora.internal.IExtTelephony;
+
public final class Utils extends com.android.settingslib.Utils {
private static final String TAG = "Settings";
@@ -134,6 +141,14 @@ public final class Utils extends com.android.settingslib.Utils {
public static final String OS_PKG = "os";
+ public static final String KEY_SOFTWARE_VERSION = "ext_meta_software_version";
+ public static final String KEY_MODEL = "ext_model_name_from_meta";
+ public static final String KEY_HARDWARE_VERSION = "ext_hardware_version";
+ public static final String KEY_WIFI_MAC_ADDRESS = "ext_wifi_mac_address";
+ public static final String KEY_DEVICE_NAME = "ext_device_name";
+ public static final String KEY_ROM_TOTAL_SIZE = "ext_rom_total_size";
+ public static final String KEY_RAM_TOTAL_SIZE = "ext_ram_total_size";
+
/**
* Whether to disable the new device identifier access restrictions.
*/
@@ -1103,6 +1118,53 @@ public final class Utils extends com.android.settingslib.Utils {
return false;
}
+ public static String getLocalizedName(Context context, String resName) {
+ if(context == null){
+ return null;
+ }
+ // If can find a localized name, replace the APN name with it
+ String localizedName = null;
+ if (resName != null && !resName.isEmpty()) {
+ int resId = context.getResources().getIdentifier(resName, "string",
+ context.getPackageName());
+ if(resId > 0){
+ try {
+ localizedName = context.getResources().getString(resId);
+ Log.d(TAG, "Replaced apn name with localized name");
+ } catch (NotFoundException e) {
+ Log.e(TAG, "Got execption while getting the localized apn name.", e);
+ }
+ }
+ }
+ return localizedName;
+ }
+
+ public static boolean carrierTableFieldValidate(String field){
+ if(field == null)
+ return false;
+ if(Telephony.Carriers.AUTH_TYPE.equalsIgnoreCase(field)
+ || Telephony.Carriers.SUBSCRIPTION_ID.equalsIgnoreCase(field))
+ return true;
+ field = field.toUpperCase();
+ Class clazz = Telephony.Carriers.class;
+ try{
+ clazz.getDeclaredField(field);
+ }catch(NoSuchFieldException e){
+ Log.w(TAG, field + "is not a valid field in class Telephony.Carriers");
+ return false;
+ }
+ return true;
+ }
+
+ public static boolean isSupportCTPA(Context context) {
+ Context appContext = context.getApplicationContext();
+ return appContext.getResources().getBoolean(R.bool.config_support_CT_PA);
+ }
+
+ public static String getString(Context context, String key) {
+ return Settings.Global.getString(context.getContentResolver(), key);
+ }
+
/** Get {@link Resources} by subscription id if subscription id is valid. */
public static Resources getResourcesForSubId(Context context, int subId) {
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
diff --git a/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java b/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java
index 670b5a8ffd..4147a7022b 100644
--- a/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java
+++ b/src/com/android/settings/applications/manageapplications/ResetAppsHelper.java
@@ -21,6 +21,8 @@ import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.INotificationManager;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
diff --git a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
index 27d63bfdb7..18057a5631 100644
--- a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
@@ -93,6 +93,19 @@ public class AvailableMediaBluetoothDeviceUpdater extends BluetoothDeviceUpdater
Log.d(TAG, "isFilterMatched() device : " +
cachedDevice.getName() + ", isFilterMatched : " + isFilterMatched);
}
+ if (isFilterMatched) {
+ if (isGroupDevice(cachedDevice)) {
+ isFilterMatched = false;
+ if (DBG) {
+ Log.d(TAG, "It is GroupDevice ignore showing ");
+ }
+ } else if (isPrivateAddr(cachedDevice)) {
+ isFilterMatched = false;
+ if (DBG) {
+ Log.d(TAG, "It is isPrivateAddr ignore showing ");
+ }
+ }
+ }
}
return isFilterMatched;
}
diff --git a/src/com/android/settings/bluetooth/BADeviceVolumeController.java b/src/com/android/settings/bluetooth/BADeviceVolumeController.java
new file mode 100644
index 0000000000..9267a74ca8
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BADeviceVolumeController.java
@@ -0,0 +1,277 @@
+/*
+ *Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *Not a contribution
+ */
+
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothVcp;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.media.AudioManager;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.SliderPreferenceController;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.bluetooth.VcpProfile;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnPause;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.bluetooth.HeadsetProfile;
+import android.bluetooth.BluetoothHeadset;
+import java.lang.Class;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+/**
+ * Class for preference controller that handles BADeviceVolumePreference
+ */
+public class BADeviceVolumeController extends
+ SliderPreferenceController implements CachedBluetoothDevice.Callback,
+ LifecycleObserver, OnPause, OnResume {
+
+ private static final String TAG = "BADeviceVolumeController";
+ public static final int BROADCAST_AUDIO_MASK = 0x02;
+ public static final String BLUETOOTH_ADV_AUDIO_MASK_PROP =
+ "persist.vendor.service.bt.adv_audio_mask";
+ public static final String BLUETOOTH_VCP_FOR_BROADCAST_PROP =
+ "persist.vendor.service.bt.vcpForBroadcast";
+ private static final String KEY_BA_DEVICE_VOLUME = "ba_device_volume";
+ private static final String VCACHED_DEVICE_CLASS =
+ "com.android.settingslib.bluetooth.VendorCachedBluetoothDevice";
+
+ protected BADeviceVolumePreference mPreference;
+ private CachedBluetoothDevice mCachedDevice;
+ protected LocalBluetoothProfileManager mProfileManager;
+ private LocalBluetoothManager mLocalBluetoothManager;
+ private VcpProfile mVcpProfile = null;
+ private boolean mIsVcpForBroadcastSupported = false;
+ private HeadsetProfile mHeadsetProfile;
+ private Class<?> mVCachedDeviceClass = null;
+ private Object mVendorCachedDevice = null;
+ @VisibleForTesting
+ AudioManager mAudioManager;
+
+ public BADeviceVolumeController(Context context) {
+ super(context, KEY_BA_DEVICE_VOLUME);
+ int advAudioMask = SystemProperties.getInt(BLUETOOTH_ADV_AUDIO_MASK_PROP, 0);
+ mIsVcpForBroadcastSupported =
+ (((advAudioMask & BROADCAST_AUDIO_MASK) == BROADCAST_AUDIO_MASK) &&
+ SystemProperties.getBoolean(BLUETOOTH_VCP_FOR_BROADCAST_PROP, false));
+ Log.d(TAG, "mIsVcpForBroadcastSupported: " + mIsVcpForBroadcastSupported);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ Log.d(TAG, "getAvailabilityStatus");
+ if(mIsVcpForBroadcastSupported) {
+ return AVAILABLE;
+ } else {
+ return UNSUPPORTED_ON_DEVICE;
+ }
+ }
+
+ @Override
+ public boolean isSliceable() {
+ return TextUtils.equals(getPreferenceKey(), KEY_BA_DEVICE_VOLUME);
+ }
+
+ @Override
+ public boolean isPublicSlice() {
+ return true;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ if (isAvailable()) {
+ mPreference = screen.findPreference(getPreferenceKey());
+ if (mAudioManager != null) {
+ mPreference.setMax(mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
+ mPreference.setMin(mAudioManager.getStreamMinVolume(AudioManager.STREAM_MUSIC));
+ refresh();
+ } else {
+ mPreference.setVisible(false);
+ }
+ }
+ }
+
+ @Override
+ public void onPause() {
+ Log.d(TAG, "onPause");
+ if (mCachedDevice != null) {
+ mCachedDevice.unregisterCallback(this);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ Log.d(TAG, "onResume");
+ if (mCachedDevice != null) {
+ mCachedDevice.registerCallback(this);
+ refresh();
+ }
+ }
+
+ public void init(DashboardFragment fragment, LocalBluetoothManager manager,
+ CachedBluetoothDevice device) {
+ Log.d(TAG, "Init");
+ if (mIsVcpForBroadcastSupported) {
+ mCachedDevice = device;
+ mLocalBluetoothManager = manager;
+ mProfileManager = mLocalBluetoothManager.getProfileManager();
+ mVcpProfile = mProfileManager.getVcpProfile();
+ mAudioManager = mContext.getSystemService(AudioManager.class);
+
+ try {
+ mVCachedDeviceClass = Class.forName(VCACHED_DEVICE_CLASS);
+ Class[] arg = new Class[2];
+ arg[0] = CachedBluetoothDevice.class;
+ arg[1] = LocalBluetoothProfileManager.class;
+ Method getVendorCachedBluetoothDevice = mVCachedDeviceClass.getDeclaredMethod(
+ "getVendorCachedBluetoothDevice", arg);
+ mVendorCachedDevice = (Object)getVendorCachedBluetoothDevice.invoke(
+ null, mCachedDevice, mProfileManager);
+ } catch (ClassNotFoundException | NoSuchMethodException
+ | IllegalAccessException | InvocationTargetException e) {
+ e.printStackTrace();
+ }
+ mHeadsetProfile = mProfileManager.getHeadsetProfile();
+ }
+ }
+
+ protected void refresh() {
+ Log.d(TAG, "refresh");
+ if (!mIsVcpForBroadcastSupported || mVcpProfile == null) {
+ Log.d(TAG, "VCP for broadcast is not supported");
+ return;
+ }
+ boolean showSlider = enableSlider();
+ BluetoothDevice device = mCachedDevice.getDevice();
+ int audioState = mHeadsetProfile.getAudioState(device);
+ boolean inCall = (audioState == BluetoothHeadset.STATE_AUDIO_CONNECTING ||
+ audioState == BluetoothHeadset.STATE_AUDIO_CONNECTED);
+ Log.d(TAG,"VCP refresh showSlider: " + showSlider + " inCall: " + inCall);
+ if ((mVcpProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED) &&
+ ((mVcpProfile.getConnectionMode(device) & BluetoothVcp.MODE_BROADCAST) != 0)) {
+ Log.d(TAG, "VCP is connected for broadcast ");
+ mPreference.setVisible(true);
+ if (!showSlider || inCall) {
+ mPreference.setProgress(0);
+ mPreference.setEnabled(false);
+ return;
+ }
+ mPreference.setEnabled(true);
+ int position = mVcpProfile.getAbsoluteVolume(device);
+
+ if (position != -1) {
+ mPreference.setProgress(position);
+ }
+ } else {
+ mPreference.setVisible(false);
+ }
+ }
+
+ @Override
+ public void onDeviceAttributesChanged() {
+ refresh();
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_BA_DEVICE_VOLUME;
+ }
+
+ @Override
+ public int getSliderPosition() {
+ if (mPreference != null) {
+ return mPreference.getProgress();
+ }
+ if (mVcpProfile != null) {
+ return mVcpProfile.getAbsoluteVolume(mCachedDevice.getDevice());
+ }
+ return 0;
+ }
+
+ @Override
+ public boolean setSliderPosition(int position) {
+ if (mPreference != null) {
+ mPreference.setProgress(position);
+ }
+ if (mVcpProfile != null) {
+ mVcpProfile.setAbsoluteVolume(mCachedDevice.getDevice(), position);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public int getMax() {
+ if (mPreference != null) {
+ return mPreference.getMax();
+ }
+ if (mAudioManager != null) {
+ return mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ }
+ return 0;
+ }
+
+ @Override
+ public int getMin() {
+ if (mPreference != null) {
+ return mPreference.getMin();
+ }
+ if (mAudioManager != null) {
+ return mAudioManager.getStreamMinVolume(AudioManager.STREAM_MUSIC);
+ }
+ return 0;
+ }
+ private boolean enableSlider() {
+ if (mVCachedDeviceClass == null || mVendorCachedDevice == null) {
+ Log.d(TAG,"enableSlider: false");
+ return false;
+ }
+
+ try {
+ Method isBroadcastAudioSynced =
+ mVCachedDeviceClass.getDeclaredMethod("isBroadcastAudioSynced");
+ Boolean ret = (Boolean)isBroadcastAudioSynced.invoke(mVendorCachedDevice);
+ Log.d(TAG,"enableSlider: " + ret);
+ return ret;
+ } catch(IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
+ Log.i(TAG, "Exception" + e);
+ }
+
+ Log.d(TAG,"enableSlider: false");
+ return false;
+ }
+}
+
diff --git a/src/com/android/settings/bluetooth/BADeviceVolumePreference.java b/src/com/android/settings/bluetooth/BADeviceVolumePreference.java
new file mode 100644
index 0000000000..add5f1b5be
--- /dev/null
+++ b/src/com/android/settings/bluetooth/BADeviceVolumePreference.java
@@ -0,0 +1,67 @@
+/*
+ *Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *Not a contribution
+ */
+
+/*
+ * Copyright (C) 2014 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.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.SeekBar;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+import com.android.settings.widget.SeekBarPreference;
+
+import java.util.Objects;
+
+/** A slider preference that directly controls an BA device volume **/
+public class BADeviceVolumePreference extends SeekBarPreference {
+ private static final String TAG = "BADeviceVolumePreference";
+
+ protected SeekBar mSeekBar;
+ private ImageView mIconView;
+
+ public BADeviceVolumePreference(Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ setLayoutResource(R.layout.preference_ba_device_volume_slider);
+ }
+
+ public BADeviceVolumePreference(Context context, AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setLayoutResource(R.layout.preference_ba_device_volume_slider);
+ }
+
+ public BADeviceVolumePreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setLayoutResource(R.layout.preference_ba_device_volume_slider);
+ }
+
+ public BADeviceVolumePreference(Context context) {
+ super(context);
+ setLayoutResource(R.layout.preference_ba_device_volume_slider);
+ }
+}
+
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
index aacf41fbbc..4c0a33dca3 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsProfilesController.java
@@ -16,9 +16,11 @@
package com.android.settings.bluetooth;
+import android.bluetooth.BluetoothCodecStatus;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
+import android.os.SystemProperties;
import android.text.TextUtils;
import androidx.annotation.VisibleForTesting;
@@ -28,8 +30,11 @@ import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
+import com.android.settings.bluetooth.GroupBluetoothProfileSwitchConfirmDialog.BluetoothProfileConfirmListener;
+
import com.android.settings.R;
import com.android.settingslib.bluetooth.A2dpProfile;
+import com.android.settingslib.bluetooth.BluetoothCallback;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfile;
@@ -40,16 +45,18 @@ import com.android.settingslib.bluetooth.PbapServerProfile;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.List;
-
/**
* This class adds switches for toggling the individual profiles that a Bluetooth device
* supports, such as "Phone audio", "Media audio", "Contact sharing", etc.
*/
public class BluetoothDetailsProfilesController extends BluetoothDetailsController
implements Preference.OnPreferenceClickListener,
- LocalBluetoothProfileManager.ServiceListener {
+ LocalBluetoothProfileManager.ServiceListener, BluetoothCallback,
+ BluetoothProfileConfirmListener {
private static final String KEY_PROFILES_GROUP = "bluetooth_profiles";
private static final String KEY_BOTTOM_PREFERENCE = "bottom_preference";
+ private static final String BLUETOOTH_PROFILE_CONFIRM_DIALOG_PROP =
+ "persist.vendor.service.bt.profile_confirm_dialog";
private static final int ORDINAL = 99;
@VisibleForTesting
@@ -62,6 +69,15 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
@VisibleForTesting
PreferenceCategory mProfilesContainer;
+ private PreferenceFragmentCompat mFragment;
+ private boolean mIsGroupDevice = false;
+ private GroupBluetoothProfileSwitchConfirmDialog mGroupBluetoothProfileConfirm;
+ private int mGroupId = -1;
+ private GroupUtils mGroupUtils;
+ private LocalBluetoothProfile mProfile;
+ private SwitchPreference mProfilePref;
+ private boolean mIsProfileConfirmDialogSupported = false;
+
public BluetoothDetailsProfilesController(Context context, PreferenceFragmentCompat fragment,
LocalBluetoothManager manager, CachedBluetoothDevice device, Lifecycle lifecycle) {
super(context, fragment, device, lifecycle);
@@ -69,6 +85,14 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
mProfileManager = mManager.getProfileManager();
mCachedDevice = device;
lifecycle.addObserver(this);
+ mFragment = fragment;
+ mGroupUtils = new GroupUtils(context);
+ mIsGroupDevice = mGroupUtils.isGroupDevice(mCachedDevice);
+ if (mIsGroupDevice) {
+ mGroupId = mGroupUtils.getGroupId(mCachedDevice);
+ }
+ mIsProfileConfirmDialogSupported =
+ SystemProperties.getBoolean(BLUETOOTH_PROFILE_CONFIRM_DIALOG_PROP, false);
}
@Override
@@ -170,23 +194,22 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
*/
@Override
public boolean onPreferenceClick(Preference preference) {
- LocalBluetoothProfile profile = mProfileManager.getProfileByName(preference.getKey());
- if (profile == null) {
+ mProfile = mProfileManager.getProfileByName(preference.getKey());
+ if (mProfile == null) {
// It might be the PbapServerProfile, which is not stored by name.
PbapServerProfile psp = mManager.getProfileManager().getPbapProfile();
if (TextUtils.equals(preference.getKey(), psp.toString())) {
- profile = psp;
+ mProfile = psp;
} else {
return false;
}
}
- SwitchPreference profilePref = (SwitchPreference) preference;
- if (profilePref.isChecked()) {
- enableProfile(profile);
+ mProfilePref = (SwitchPreference) preference;
+ if (mIsGroupDevice && mIsProfileConfirmDialogSupported) {
+ showProfileConfirmDialog();
} else {
- disableProfile(profile);
+ enableOrDisableProfile();
}
- refreshProfilePreference(profilePref, profile);
return true;
}
@@ -233,7 +256,11 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
highQualityAudioPref.setKey(HIGH_QUALITY_AUDIO_PREF_TAG);
highQualityAudioPref.setVisible(false);
highQualityAudioPref.setOnPreferenceClickListener(clickedPref -> {
+ highQualityAudioPref.setEnabled(false);
boolean enable = ((SwitchPreference) clickedPref).isChecked();
+ if ((a2dp.isMandatoryCodec(device) && !enable) ||
+ (!a2dp.isMandatoryCodec(device) && enable))
+ highQualityAudioPref.setEnabled(true);
a2dp.setHighQualityAudioEnabled(mCachedDevice.getDevice(), enable);
return true;
});
@@ -245,12 +272,14 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
public void onPause() {
super.onPause();
mProfileManager.removeServiceListener(this);
+ mManager.getEventManager().unregisterCallback(this);
}
@Override
public void onResume() {
super.onResume();
mProfileManager.addServiceListener(this);
+ mManager.getEventManager().registerCallback(this);
}
@Override
@@ -263,6 +292,41 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
refresh();
}
+ private void updateA2dpHighQualityAudioPref() {
+ A2dpProfile a2dp = null;
+ for (LocalBluetoothProfile profile : getProfiles()) {
+ if (profile instanceof A2dpProfile) {
+ if (profile.isProfileReady()) {
+ a2dp = (A2dpProfile)profile;
+ }
+ break;
+ }
+ }
+ if (a2dp == null) {
+ return;
+ }
+
+ BluetoothDevice device = mCachedDevice.getDevice();
+ SwitchPreference highQualityPref = (SwitchPreference) mProfilesContainer.findPreference(
+ HIGH_QUALITY_AUDIO_PREF_TAG);
+ if (highQualityPref != null) {
+ if (a2dp.isEnabled(device) && a2dp.supportsHighQualityAudio(device)) {
+ highQualityPref.setTitle(a2dp.getHighQualityAudioOptionLabel(device));
+ highQualityPref.setChecked(a2dp.isHighQualityAudioEnabled(device));
+ highQualityPref.setEnabled(true);
+ }
+ }
+ }
+
+ @Override
+ public void onA2dpCodecConfigChanged(CachedBluetoothDevice cachedDevice,
+ BluetoothCodecStatus codecStatus) {
+ if (!cachedDevice.equals(mCachedDevice)) {
+ return;
+ }
+ updateA2dpHighQualityAudioPref();
+ }
+
/**
* Refreshes the state of the switches for all profiles, possibly adding or removing switches as
* needed.
@@ -306,4 +370,47 @@ public class BluetoothDetailsProfilesController extends BluetoothDetailsControll
public String getPreferenceKey() {
return KEY_PROFILES_GROUP;
}
-} \ No newline at end of file
+
+ private void initGroupBluetoothProfileConfirm() {
+ if (mIsGroupDevice) {
+ if (mGroupBluetoothProfileConfirm != null) {
+ mGroupBluetoothProfileConfirm.dismiss();
+ mGroupBluetoothProfileConfirm = null;
+ }
+ mGroupBluetoothProfileConfirm =
+ GroupBluetoothProfileSwitchConfirmDialog.newInstance(mGroupId);
+ mGroupBluetoothProfileConfirm.setPairingController(this);
+ }
+ }
+
+ @Override
+ public void onDialogNegativeClick() {
+ resetProfileSwitch();
+ mGroupBluetoothProfileConfirm.dismiss();
+ }
+
+ @Override
+ public void onDialogPositiveClick() {
+ enableOrDisableProfile();
+ mGroupBluetoothProfileConfirm.dismiss();
+ }
+
+ private void showProfileConfirmDialog() {
+ initGroupBluetoothProfileConfirm();
+ mGroupBluetoothProfileConfirm.show(mFragment.getFragmentManager(),
+ GroupBluetoothProfileSwitchConfirmDialog.TAG);
+ }
+
+ private void resetProfileSwitch() {
+ mProfilePref.setChecked(!mProfilePref.isChecked());
+ }
+
+ private void enableOrDisableProfile() {
+ if (mProfilePref.isChecked()) {
+ enableProfile(mProfile);
+ } else {
+ disableProfile(mProfile);
+ }
+ refreshProfilePreference(mProfilePref, mProfile);
+ }
+}
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
index 4980ba313f..c4232e988f 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceDetailsFragment.java
@@ -23,6 +23,7 @@ import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.os.Bundle;
+import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.util.Log;
import android.view.Menu;
@@ -30,9 +31,12 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.SettingsUIDeviceConfig;
+import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.dashboard.RestrictedDashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.slices.BlockingSlicePrefController;
@@ -41,12 +45,20 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment {
public static final String KEY_DEVICE_ADDRESS = "device_address";
private static final String TAG = "BTDeviceDetailsFrg";
+ private static final String BLUETOOTH_ADV_AUDIO_MASK_PROP
+ = "persist.vendor.service.bt.adv_audio_mask";
+ private static final String BLUETOOTH_BROADCAST_UI_PROP = "persist.bluetooth.broadcast_ui";
+ private static final int BA_MASK = 0x02;
+ private static boolean mBAEnabled = false;
+ private static boolean mBAPropertyChecked = false;
@VisibleForTesting
static int EDIT_DEVICE_NAME_ITEM_ID = Menu.FIRST;
@@ -126,6 +138,8 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
use(BlockingSlicePrefController.class).setSliceUri(sliceEnabled
? featureProvider.getBluetoothDeviceSettingsUri(mCachedDevice.getDevice())
: null);
+
+ use(BADeviceVolumeController.class).init(this, mManager, mCachedDevice);
}
@Override
@@ -176,22 +190,72 @@ public class BluetoothDeviceDetailsFragment extends RestrictedDashboardFragment
}
@Override
+ protected void displayResourceTilesToScreen(PreferenceScreen screen) {
+ if (!mBAEnabled || !mCachedDevice.isBASeeker()) {
+ screen.removePreference(screen.findPreference("sync_helper_buttons"));
+ screen.removePreference(screen.findPreference("added_sources"));
+ }
+ super.displayResourceTilesToScreen(screen);
+ }
+
+ @Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
ArrayList<AbstractPreferenceController> controllers = new ArrayList<>();
- if (mCachedDevice != null) {
- Lifecycle lifecycle = getSettingsLifecycle();
- controllers.add(new BluetoothDetailsHeaderController(context, this, mCachedDevice,
- lifecycle, mManager));
- controllers.add(new BluetoothDetailsButtonsController(context, this, mCachedDevice,
- lifecycle));
- controllers.add(new BluetoothDetailsCompanionAppsController(context, this,
- mCachedDevice, lifecycle));
- controllers.add(new BluetoothDetailsProfilesController(context, this, mManager,
- mCachedDevice, lifecycle));
- controllers.add(new BluetoothDetailsMacAddressController(context, this, mCachedDevice,
- lifecycle));
+ if (mCachedDevice == null) return controllers;
+
+ Lifecycle lifecycle = getSettingsLifecycle();
+ controllers.add(new BluetoothDetailsHeaderController(context, this, mCachedDevice,
+ lifecycle, mManager));
+ controllers.add(new BluetoothDetailsButtonsController(context, this, mCachedDevice,
+ lifecycle));
+ controllers.add(new BluetoothDetailsCompanionAppsController(context, this,
+ mCachedDevice, lifecycle));
+ controllers.add(new BluetoothDetailsProfilesController(context, this, mManager,
+ mCachedDevice, lifecycle));
+ controllers.add(new BluetoothDetailsMacAddressController(context, this, mCachedDevice,
+ lifecycle));
+ if (mBAPropertyChecked == false) {
+ int advAudioMask = SystemProperties.getInt(BLUETOOTH_ADV_AUDIO_MASK_PROP, 0);
+ mBAEnabled = (((advAudioMask & BA_MASK) == BA_MASK) &&
+ SystemProperties.getBoolean(BLUETOOTH_BROADCAST_UI_PROP, true));
+ mBAPropertyChecked = true;
+ }
+ if (mBAEnabled == false) {
+ return controllers;
+ }
+
+ Log.d(TAG, "createPreferenceControllers for BA");
+
+ try {
+ if (mCachedDevice.isBASeeker()) {
+ Class<?> classAddSourceController = Class.forName(
+ "com.android.settings.bluetooth.BluetoothDetailsAddSourceButtonController");
+ Class<?> classBADeviceController = Class.forName(
+ "com.android.settings.bluetooth.BADevicePreferenceController");
+ Constructor ctorAddSource = classAddSourceController
+ .getDeclaredConstructor(new Class[] {Context.class,
+ PreferenceFragmentCompat.class, CachedBluetoothDevice.class, Lifecycle.class});
+ Constructor ctorBADevice = classBADeviceController
+ .getDeclaredConstructor(new Class[] {Context.class, Lifecycle.class,
+ String.class});
+ Object objAddSourceController = ctorAddSource.newInstance(context, this,
+ mCachedDevice, lifecycle);
+ Object objBADeviceController = ctorBADevice.newInstance(context, lifecycle,
+ "added_sources");
+ objBADeviceController.getClass()
+ .getMethod("init", DashboardFragment.class, CachedBluetoothDevice.class)
+ .invoke(objBADeviceController, this, mCachedDevice);
+ controllers.add((AbstractPreferenceController) objAddSourceController);
+ controllers.add((AbstractPreferenceController) objBADeviceController);
+ }
+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
+ InvocationTargetException | InstantiationException | IllegalArgumentException |
+ ExceptionInInitializerError e) {
+ e.printStackTrace();
+ mBAEnabled = false;
+ } finally {
+ return controllers;
}
- return controllers;
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
index 3e50049e1e..6751b4038c 100644
--- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
+++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java
@@ -20,6 +20,7 @@ import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
import android.app.settings.SettingsEnums;
import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Resources;
@@ -92,6 +93,8 @@ public final class BluetoothDevicePreference extends GearPreference {
}
}
+ private final boolean mHideSummary;
+
public BluetoothDevicePreference(Context context, CachedBluetoothDevice cachedDevice,
boolean showDeviceWithoutNames, @SortType int type) {
super(context, null);
@@ -110,7 +113,28 @@ public final class BluetoothDevicePreference extends GearPreference {
mCachedDevice.registerCallback(mCallback);
mCurrentTime = System.currentTimeMillis();
mType = type;
+ onPreferenceAttributesChanged();
+ mHideSummary = false;
+ }
+ public BluetoothDevicePreference(Context context, CachedBluetoothDevice cachedDevice,
+ boolean showDeviceWithoutNames, @SortType int type, boolean hideSummary) {
+ super(context, null);
+ mResources = getContext().getResources();
+ mUserManager = context.getSystemService(UserManager.class);
+ mShowDevicesWithoutNames = showDeviceWithoutNames;
+ if (sDimAlpha == Integer.MIN_VALUE) {
+ TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
+ sDimAlpha = (int) (outValue.getFloat() * 255);
+ }
+
+ mCachedDevice = cachedDevice;
+ mCallback = new BluetoothDevicePreferenceCallback();
+ mCachedDevice.registerCallback(mCallback);
+ mCurrentTime = System.currentTimeMillis();
+ mType = type;
+ mHideSummary = hideSummary;
onPreferenceAttributesChanged();
}
@@ -185,12 +209,26 @@ public final class BluetoothDevicePreference extends GearPreference {
* changed before proceeding. It will also call notifyChanged() if
* any preference info has changed from the previous value.
*/
- setTitle(mCachedDevice.getName());
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ if (adapter != null &&
+ mCachedDevice.getAddress().equals(adapter.getAddress())) {
+ //for ba related things, using the same preference
+ //for showing the local device
+ setTitle(adapter.getName()+"(self)");
+ } else {
+ setTitle(mCachedDevice.getName());
+ }
// Null check is done at the framework
- setSummary(mCachedDevice.getConnectionSummary());
+ if (!mHideSummary) {
+ setSummary(mCachedDevice.getConnectionSummary());
+ }
// Used to gray out the item
- setEnabled(!mCachedDevice.isBusy());
+ if (mHideSummary) {
+ setEnabled(true);
+ } else {
+ setEnabled(!mCachedDevice.isBusy());
+ }
// Device is only visible in the UI if it has a valid name besides MAC address or when user
// allows showing devices without user-friendly name in developer settings
diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
index d65500be27..b514ec7125 100644
--- a/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/BluetoothDeviceUpdater.java
@@ -40,6 +40,7 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import java.util.UUID;
/**
* Update the bluetooth devices. It gets bluetooth event from {@link LocalBluetoothManager} using
@@ -62,8 +63,10 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback,
@VisibleForTesting
protected LocalBluetoothManager mLocalManager;
+ private GroupUtils mGroupUtils;
+
@VisibleForTesting
- final GearPreference.OnGearClickListener mDeviceProfilesListener = pref -> {
+ public final GearPreference.OnGearClickListener mDeviceProfilesListener = pref -> {
launchDeviceDetails(pref);
};
@@ -80,6 +83,7 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback,
mPreferenceMap = new HashMap<>();
mLocalManager = localManager;
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
+ mGroupUtils = new GroupUtils(context);
}
/**
@@ -187,6 +191,16 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback,
}
@Override
+ public void onNewGroupFound(CachedBluetoothDevice cachedDevice, int groupId,
+ UUID setPrimaryServiceUuid) {
+ if (DBG) {
+ Log.d(TAG, " NewGroupFound device: " + cachedDevice
+ + ", groupId: " + groupId);
+ }
+ update(cachedDevice);
+ }
+
+ @Override
public void onServiceConnected() {
// When bluetooth service connected update the UI
forceUpdate();
@@ -326,4 +340,17 @@ public abstract class BluetoothDeviceUpdater implements BluetoothCallback,
((BluetoothDevicePreference) preference).onPreferenceAttributesChanged();
}
}
+
+ public boolean isGroupDevice(CachedBluetoothDevice cachedDevice) {
+ return mGroupUtils.isGroupDevice(cachedDevice);
+ }
+
+ public boolean isPrivateAddr(CachedBluetoothDevice cachedDevice) {
+ boolean isPvtAddr = cachedDevice.isPrivateAddr();
+ if (DBG) {
+ Log.d(TAG, "isPrivateAddr device name : " + cachedDevice.getName()
+ + " isPvtAddr " + isPvtAddr);
+ }
+ return isPvtAddr;
+ }
}
diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java
index d489198103..be6cf66a0f 100644
--- a/src/com/android/settings/bluetooth/BluetoothEnabler.java
+++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java
@@ -136,19 +136,19 @@ public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchCh
mSwitchController.setEnabled(false);
break;
case BluetoothAdapter.STATE_ON:
- setChecked(true);
mSwitchController.setEnabled(true);
+ setChecked(true);
break;
case BluetoothAdapter.STATE_TURNING_OFF:
mSwitchController.setEnabled(false);
break;
case BluetoothAdapter.STATE_OFF:
- setChecked(false);
mSwitchController.setEnabled(true);
+ setChecked(false);
break;
default:
- setChecked(false);
mSwitchController.setEnabled(true);
+ setChecked(false);
}
}
diff --git a/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java
index 74c39b6f8c..7848fa4d86 100644
--- a/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothNameDialogFragment.java
@@ -89,7 +89,7 @@ abstract class BluetoothNameDialogFragment extends InstrumentedDialogFragment
.setTitle(getDialogTitle())
.setView(createDialogView(deviceName))
.setPositiveButton(R.string.bluetooth_rename_button, (dialog, which) -> {
- setDeviceName(mDeviceNameView.getText().toString());
+ setDeviceName(mDeviceNameView.getText().toString().trim());
})
.setNegativeButton(android.R.string.cancel, null);
mAlertDialog = builder.create();
@@ -133,7 +133,11 @@ abstract class BluetoothNameDialogFragment extends InstrumentedDialogFragment
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_ACTION_DONE) {
- setDeviceName(v.getText().toString());
+ // Rejecting Empty String
+ if (v.length() != 0 && !(v.getText().toString().trim().isEmpty()))
+ {
+ setDeviceName(v.getText().toString());
+ }
if (mAlertDialog != null && mAlertDialog.isShowing()) {
mAlertDialog.dismiss();
}
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingController.java b/src/com/android/settings/bluetooth/BluetoothPairingController.java
index ca3dda6738..3bce36b9ec 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingController.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingController.java
@@ -63,7 +63,6 @@ public class BluetoothPairingController implements OnCheckedChangeListener,
private int mInitiator;
private String mDeviceName;
private LocalBluetoothProfile mPbapClientProfile;
- private boolean mPbapAllowed;
/**
* Creates an instance of a BluetoothPairingController.
@@ -95,20 +94,14 @@ public class BluetoothPairingController implements OnCheckedChangeListener,
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
- mPbapAllowed = true;
+ mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
} else {
- mPbapAllowed = false;
+ mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
}
}
@Override
public void onDialogPositiveClick(BluetoothPairingDialogFragment dialog) {
- if (mPbapAllowed) {
- mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
- } else {
- mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
- }
-
if (getDialogType() == USER_ENTRY_DIALOG) {
onPair(mUserInput);
} else {
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingService.java b/src/com/android/settings/bluetooth/BluetoothPairingService.java
index bc5dc6695d..40d446a975 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingService.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingService.java
@@ -200,7 +200,12 @@ public final class BluetoothPairingService extends Service {
String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
if (TextUtils.isEmpty(name)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
- name = device != null ? device.getAlias() : res.getString(android.R.string.unknownName);
+ if (device != null) {
+ name = device.getAlias() != null ? device.getAlias():
+ device.getAddress();
+ } else {
+ name = res.getString(android.R.string.unknownName);
+ }
}
Log.d(TAG, "Show pairing notification for " + " (" + name + ")");
diff --git a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
index fc1b9b734b..31d9b1e3e6 100644
--- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
@@ -94,6 +94,19 @@ public class ConnectedBluetoothDeviceUpdater extends BluetoothDeviceUpdater {
Log.d(TAG, "isFilterMatched() device : " +
cachedDevice.getName() + ", isFilterMatched : " + isFilterMatched);
}
+ if (isFilterMatched) {
+ if (isGroupDevice(cachedDevice)) {
+ isFilterMatched = false;
+ if (DBG) {
+ Log.d(TAG, "It is isGroupDevice ignore showing ");
+ }
+ } else if (isPrivateAddr(cachedDevice)) {
+ isFilterMatched = false;
+ if (DBG) {
+ Log.d(TAG, "It is isPrivateAddr ignore showing ");
+ }
+ }
+ }
}
return isFilterMatched;
}
diff --git a/src/com/android/settings/bluetooth/DevicePickerFragment.java b/src/com/android/settings/bluetooth/DevicePickerFragment.java
index 602b79b2ae..382dee4487 100644
--- a/src/com/android/settings/bluetooth/DevicePickerFragment.java
+++ b/src/com/android/settings/bluetooth/DevicePickerFragment.java
@@ -204,6 +204,7 @@ public final class DevicePickerFragment extends DeviceListPreferenceFragment {
}
private void sendDevicePickedIntent(BluetoothDevice device) {
+ android.util.Log.d("Devicepicker", "sendDevicePickedIntent");
Intent intent = new Intent(BluetoothDevicePicker.ACTION_DEVICE_SELECTED);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
if (mLaunchPackage != null && mLaunchClass != null) {
@@ -211,6 +212,7 @@ public final class DevicePickerFragment extends DeviceListPreferenceFragment {
intent.setClassName(mLaunchPackage, mLaunchClass);
}
}
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcast(intent, Manifest.permission.BLUETOOTH_CONNECT);
}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothDetailsButtonsController.java b/src/com/android/settings/bluetooth/GroupBluetoothDetailsButtonsController.java
new file mode 100644
index 0000000000..84ec93f9ab
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothDetailsButtonsController.java
@@ -0,0 +1,332 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothDeviceGroup;
+import android.content.Context;
+import android.util.Log;
+import android.view.View;
+
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceScreen;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.android.settings.R;
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
+import com.android.settings.widget.GroupOptionsPreference;
+import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+/**
+ * This class adds Group action buttons: one to connect/disconnect from a device
+ * (depending on the current connected state of all devices in this group ), and
+ * one to "forget" (ie unpair) the device and one for to refresh devices.
+*/
+public class GroupBluetoothDetailsButtonsController extends GroupBluetoothDetailsController {
+
+ private static final boolean DBG = ConnectedDeviceDashboardFragment.DBG_GROUP;
+ private static String TAG = "GroupBluetoothDetailsButtonsController";
+ private static final String KEY_GROUP_OPTIONS = "group_options";
+ private boolean mConnectButtonInitialized;
+ private GroupOptionsPreference mGroupOptions;
+ private boolean mIsUpdate = false;
+ private int mGroupId;
+ private GroupUtils mGroupUtils;
+ private int mGroupSize = -1;
+ private int mDiscoveredSize = 0;
+ private boolean isRefreshClicked = false;
+ private ArrayList<CachedBluetoothDevice> mDevicesList = new ArrayList<CachedBluetoothDevice>();
+
+
+ public GroupBluetoothDetailsButtonsController(Context context,
+ PreferenceFragmentCompat fragment, int groupId, Lifecycle lifecycle) {
+ super(context, fragment, groupId, lifecycle);
+ mGroupId = groupId;
+ mGroupUtils = new GroupUtils(context);
+ mGroupSize = mGroupUtils.getGroupSize(mGroupId);
+ }
+
+ @Override
+ protected void init(PreferenceScreen screen) {
+ if (DBG) {
+ Log.d(TAG, "init ");
+ }
+ mGroupOptions = ((GroupOptionsPreference)
+ screen.findPreference(getPreferenceKey()));
+ mGroupOptions.setTextViewText(mContext.getString(R.string.group_id)
+ + mGroupUtils.getGroupTitle(mGroupId));
+ mGroupOptions.setForgetButtonText(R.string.forget_group);
+ mGroupOptions.setForgetButtonOnClickListener((View) -> onForgetButtonPressed());
+ mGroupOptions.setForgetButtonEnabled(true);
+ mGroupOptions.setTexStatusText(R.string.active);
+ mGroupOptions.setConnectButtonText(R.string.connect_group);
+ mGroupOptions.setConnectButtonOnClickListener((View) -> onConnectButtonPressed());
+ mGroupOptions.setDisconnectButtonText(R.string.disconnect_group);
+ mGroupOptions.setDisconnectButtonOnClickListener((View) -> onDisConnectButtonPressed());
+ mGroupOptions.setCancelRefreshButtonText(R.string.cancel_refresh_group);
+ mGroupOptions.setCancelRefreshButtonOnClickListener(
+ (View) -> onCacelRefreshButtonPressed());
+ mGroupOptions.setCancelRefreshButtonVisible(false);
+ mGroupOptions.setRefreshButtonText(R.string.refresh_group);
+ mGroupOptions.setRefreshButtonOnClickListener((View) -> onRefreshButtonPressed());
+ mGroupOptions.setRefreshButtonVisible(false);
+ mIsUpdate = true;
+
+ BluetoothDevice bcMemberDevice = mGroupUtils.getAnyBCConnectedDevice(mGroupId);
+ boolean enableASButton = false;
+ if (bcMemberDevice != null) {
+ enableASButton = true;
+ }
+ mGroupOptions.setAddSourceGroupButtonText(R.string.add_source_group);
+ mGroupOptions.setAddSourceGroupButtonEnabled(enableASButton);
+ mGroupOptions.setAddSourceGroupButtonVisible(enableASButton);
+ if (enableASButton) {
+ mGroupOptions.setAddSourceGroupButtonOnClickListener((View) ->
+ onAddSourceGroupButtonPressed());
+ }
+ }
+
+ private void onAddSourceGroupButtonPressed() {
+ mGroupUtils.launchAddSourceGroup(mGroupId);
+ }
+
+ @Override
+ public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
+ if (DBG) {
+ Log.d(TAG, "onConnectionStateChanged cachedDevice "+cachedDevice +" state "+state);
+ }
+ if (mGroupUtils.isUpdate(mGroupId, cachedDevice)) {
+ refresh();
+ }
+ }
+
+ @Override
+ public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice,
+ int state, int bluetoothProfile) {
+ if (DBG) {
+ Log.d(TAG, "onProfileConnectionStateChanged cachedDevice " + cachedDevice
+ + " state " + state);
+ }
+ if (mGroupUtils.isUpdate(mGroupId, cachedDevice)) {
+ refresh();
+ }
+ }
+
+ @Override
+ public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
+ boolean isUpdated = false;
+ if (bondState == BluetoothDevice.BOND_BONDED) {
+ isUpdated = mGroupUtils.addDevice(mDevicesList, mGroupId, cachedDevice);
+ } else if (bondState == BluetoothDevice.BOND_NONE) {
+ isUpdated = mGroupUtils.removeDevice(mDevicesList, mGroupId, cachedDevice);
+ }
+ if (isUpdated) {
+ mDiscoveredSize = mDevicesList.size();
+ }
+ if (DBG) {
+ Log.d(TAG, "onDeviceBondStateChanged cachedDevice " + cachedDevice
+ + " name " + cachedDevice.getName() + " bondState " + bondState
+ +" isUpdated " + isUpdated + " mDiscoveredSize " + mDiscoveredSize);
+ }
+ if (isUpdated) {
+ updateProgressScan();
+ refresh();
+ }
+ }
+ @Override
+ public void onStop() {
+ if (DBG) {
+ Log.d(TAG, "onStop ");
+ }
+ super.onStop();
+ disableScanning();
+ }
+
+ @Override
+ public void onGroupDiscoveryStatusChanged (int groupId, int status, int reason) {
+ if (DBG) {
+ Log.d(TAG, "onSetDiscoveryStatusChanged " + groupId + " status :" + status
+ + " Reason :" + reason);
+ }
+ if (groupId == mGroupId) {
+ if (isRefreshClicked && status == BluetoothDeviceGroup.GROUP_DISCOVERY_STOPPED ) {
+ isRefreshClicked = false;
+ }
+ updateProgressScan();
+ }
+ }
+
+ @Override
+ protected void loadDevices() {
+ mDevicesList = mGroupUtils.getCahcedDevice(mGroupId);
+ mDiscoveredSize = mDevicesList.size();
+ if (DBG) {
+ Log.d(TAG, "loadDevices mGroupId " + mGroupId + " mGroupSize " + mGroupSize
+ + " mDiscoveredSize " + mDiscoveredSize);
+ }
+ updateProgressScan();
+ }
+
+ @Override
+ protected void refresh() {
+ boolean isBusy = false;
+ boolean showConnect = false;
+ boolean showDisconnect = false;
+ boolean isActive = false;
+ List<CachedBluetoothDevice> devicesList = new ArrayList<>(mDevicesList);
+ if (DBG) {
+ Log.d(TAG, "updateFlags list " + devicesList + " size " + devicesList.size());
+ }
+ for (CachedBluetoothDevice cacheDevice : devicesList) {
+ if (DBG) {
+ Log.d(TAG, "refresh cacheDevice " + cacheDevice + " connected "
+ + cacheDevice.isConnected() +" busy " + cacheDevice.isBusy());
+ }
+ if (!isBusy && cacheDevice.isBusy()) {
+ isBusy = true;
+ mIsUpdate = true;
+ }
+ if (!showDisconnect && cacheDevice.isConnected()) {
+ showDisconnect = true;
+ mIsUpdate = true;
+ } else if (!showConnect && !cacheDevice.isConnected()) {
+ showConnect = true;
+ mIsUpdate = true;
+ } if((!isActive) && cacheDevice.isConnected()
+ && (cacheDevice.isActiveDevice(BluetoothProfile.A2DP)
+ || cacheDevice.isActiveDevice(BluetoothProfile.HEADSET)
+ || cacheDevice.isActiveDevice(BluetoothProfile.HEARING_AID))) {
+ isActive = true;
+ }
+ }
+ if (DBG) {
+ Log.d(TAG, "refresh isBusy " + isBusy + " showConnect " + showConnect
+ + " showDisconnect :" + showDisconnect +" isActive " + isActive
+ + " mIsUpdate " + mIsUpdate);
+ }
+ if (!mIsUpdate) {
+ return;
+ }
+ mGroupOptions.setConnectButtonEnabled(!isBusy);
+ mGroupOptions.setDisconnectButtonEnabled(!isBusy);
+ mGroupOptions.setRefreshButtonEnabled(!isBusy);
+ mGroupOptions.setCancelRefreshButtonEnabled(!isBusy);
+ mGroupOptions.setDisconnectButtonEnabled(showDisconnect);
+ mGroupOptions.setDisconnectButtonVisible(showDisconnect);
+ mGroupOptions.setConnectButtonEnabled(showConnect);
+ mGroupOptions.setConnectButtonVisible(showConnect);
+ mGroupOptions.setTvStatusVisible(isActive);
+ mIsUpdate = false;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_GROUP_OPTIONS;
+ }
+
+ private void onForgetButtonPressed() {
+ if (DBG) {
+ Log.d(TAG, "onForgetButtonPressed");
+ }
+ GroupForgetDialogFragment fragment = GroupForgetDialogFragment.newInstance(mGroupId);
+ fragment.show(mFragment.getFragmentManager(), GroupForgetDialogFragment.TAG);
+ }
+
+ private void onConnectButtonPressed() {
+ disableScanning();
+ boolean connect = mGroupUtils.connectGroup(mGroupId);
+ if (DBG) {
+ Log.d(TAG, "onConnectButtonPressed connect " + connect);
+ }
+ }
+
+ private void onDisConnectButtonPressed() {
+ disableScanning();
+ boolean disconnect = mGroupUtils.disconnectGroup(mGroupId);
+ if (DBG) {
+ Log.d(TAG, "onDisConnectButtonPressed disconnect " + disconnect);
+ }
+ }
+
+ private void onRefreshButtonPressed() {
+ isRefreshClicked = mGroupUtils.startGroupDiscovery(mGroupId);
+ if (DBG) {
+ Log.d(TAG, "onRefreshButtonPressed isRefreshClicked " + isRefreshClicked);
+ }
+
+ }
+
+ private void onCacelRefreshButtonPressed() {
+ isRefreshClicked = false;
+ boolean stopDiscovery = mGroupUtils.stopGroupDiscovery(mGroupId);
+ if (DBG) {
+ Log.d(TAG, "onCacelRefreshButtonPressed stopDiscovery " + stopDiscovery);
+ }
+ }
+
+ private void updateProgressScan() {
+ boolean showRefresh = false;
+ if ((mGroupSize >0) && (mGroupSize > mDiscoveredSize)) {
+ showRefresh = true;
+ }
+ boolean isRefreshing = mGroupUtils.isGroupDiscoveryInProgress(mGroupId);
+ if (showRefresh) {
+ if (isRefreshing) {
+ mGroupOptions.setProgressScanVisible(true);
+ mGroupOptions.setRefreshButtonVisible(false);
+ mGroupOptions.setCancelRefreshButtonVisible(true);
+ } else {
+ mGroupOptions.setProgressScanVisible(false);
+ mGroupOptions.setRefreshButtonVisible(true);
+ mGroupOptions.setCancelRefreshButtonVisible(false);
+ }
+ } else {
+ mGroupOptions.setProgressScanVisible(showRefresh);
+ mGroupOptions.setCancelRefreshButtonVisible(showRefresh);
+ mGroupOptions.setRefreshButtonVisible(showRefresh);
+ }
+ if (DBG) {
+ Log.d(TAG, "updateProgressScan showRefresh " + showRefresh
+ + ", isRefreshing " + isRefreshing + " mDiscoveredSize " + mDiscoveredSize);
+ }
+ }
+
+ private void disableScanning () {
+ if (isRefreshClicked) {
+ mGroupUtils.stopGroupDiscovery(mGroupId);
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothDetailsController.java b/src/com/android/settings/bluetooth/GroupBluetoothDetailsController.java
new file mode 100644
index 0000000000..431dc84130
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothDetailsController.java
@@ -0,0 +1,101 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.android.settings.bluetooth;
+
+import androidx.preference.PreferenceFragmentCompat;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+import android.content.Context;
+
+public abstract class GroupBluetoothDetailsController extends AbstractPreferenceController
+ implements PreferenceControllerMixin, LifecycleObserver,
+ OnStop, OnStart, BluetoothCallback {
+
+ protected final Context mContext;
+ protected final PreferenceFragmentCompat mFragment;
+ protected LocalBluetoothManager mLocalManager;
+
+
+ public GroupBluetoothDetailsController(Context context, PreferenceFragmentCompat fragment,
+ int groupId, Lifecycle lifecycle) {
+ super(context);
+ mContext = context;
+ mFragment = fragment;
+ lifecycle.addObserver(this);
+ mLocalManager = Utils.getLocalBtManager(mContext);
+ }
+
+ @Override
+ public void onStart() {
+ mLocalManager.getEventManager().registerCallback(this);
+ loadDevices();
+ refresh();
+ }
+
+ @Override
+ public void onStop() {
+ mLocalManager.getEventManager().unregisterCallback(this);
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public final void displayPreference(PreferenceScreen screen) {
+ init(screen);
+ super.displayPreference(screen);
+ }
+
+ /**
+ * This is a method to do one-time initialization when the screen is first created, such as
+ * adding preferences.
+ * @param screen the screen where this controller's preferences should be added
+ */
+ protected abstract void init(PreferenceScreen screen);
+
+ /**
+ * This method is called when something about the bluetooth device has changed, and this object
+ * should update the preferences it manages based on the new state.
+ */
+ protected abstract void refresh();
+
+ protected abstract void loadDevices();
+}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/GroupBluetoothDeviceUpdater.java
new file mode 100644
index 0000000000..1284f223c0
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothDeviceUpdater.java
@@ -0,0 +1,96 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.bluetooth.BluetoothDevicePreference;
+import com.android.settings.bluetooth.BluetoothDeviceUpdater;
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.GearPreference;
+import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Update the Group bluetooth devices. It gets bluetooth event from {@link LocalBluetoothManager}
+ * using {@link BluetoothCallback}. It notifies the upper level whether to add/remove the
+ * preference through {@link DevicePreferenceCallback}
+ *
+ * In {@link GroupBluetoothDeviceUpdater}, it uses {@link BluetoothDeviceFilter.Filter} to detect
+ * whether the {@link CachedBluetoothDevice} is relevant.
+ */
+public abstract class GroupBluetoothDeviceUpdater extends BluetoothDeviceUpdater {
+ private static final String TAG = "GroupBluetoothDeviceUpdater";
+ protected static final boolean DBG = ConnectedDeviceDashboardFragment.DBG_GROUP;
+
+ public GroupBluetoothDeviceUpdater(Context context, DashboardFragment fragment,
+ DevicePreferenceCallback devicePreferenceCallback) {
+ super(context, fragment, devicePreferenceCallback);
+ }
+
+ @Override
+ protected void addPreference(CachedBluetoothDevice cachedDevice) {
+ addPreference(cachedDevice, BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+ }
+
+ public void launchgroupOptions(Preference preference) {
+ if (DBG)
+ Log.d(TAG, " launchgroupOptions :" + preference);
+ mMetricsFeatureProvider.logClickedPreference(preference, mFragment.getMetricsCategory());
+ final GroupBluetoothSettingsPreference pref =
+ (GroupBluetoothSettingsPreference) preference;
+ final Bundle args = new Bundle();
+ args.putInt(GroupBluetoothFragment.KEY_GROUP_ID, pref.getGroupId());
+ new SubSettingLauncher(mFragment.getContext()).setDestination
+ (GroupBluetoothFragment.class.getName())
+ .setArguments(args).setTitleRes(R.string.group_options)
+ .setSourceMetricsCategory(mFragment.getMetricsCategory()).launch();
+ }
+
+}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothDevicesAvailableMediaController.java b/src/com/android/settings/bluetooth/GroupBluetoothDevicesAvailableMediaController.java
new file mode 100644
index 0000000000..8a4eaa29f2
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothDevicesAvailableMediaController.java
@@ -0,0 +1,134 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.android.settings.bluetooth;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import androidx.preference.PreferenceFragmentCompat;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+import com.android.settings.bluetooth.BluetoothDevicePreference;
+import com.android.settings.bluetooth.BluetoothDeviceUpdater;
+import com.android.settings.bluetooth.GroupSavedBluetoothDeviceUpdater;
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.connecteddevice.dock.DockUpdater;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.DockUpdaterFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.GearPreference;
+import com.android.settings.widget.GearPreference.OnGearClickListener;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+
+import android.util.Log;
+import com.android.settings.R;
+
+/**
+ * Controller to maintain available Group devices
+ */
+public class GroupBluetoothDevicesAvailableMediaController extends BasePreferenceController
+ implements PreferenceControllerMixin,
+ LifecycleObserver, OnStart, OnStop, DevicePreferenceCallback {
+
+ private static final boolean DBG = ConnectedDeviceDashboardFragment.DBG_GROUP;
+ private static final String KEY = "group_options_active_devices";
+ private static final String TAG = "GroupBluetoothDevicesAvailableMediaController";
+ private PreferenceGroup mPreferenceGroup;
+ private GroupBluetoothDevicesAvailableMediaDeviceUpdater mGroupDeviceUpdater;
+ private int mGroupId;
+
+ public GroupBluetoothDevicesAvailableMediaController(Context context, DashboardFragment
+ fragment, Lifecycle lifecycle, int groupId) {
+ super(context, KEY);
+ mGroupId = groupId;
+ lifecycle.addObserver(this);
+ mGroupDeviceUpdater = new GroupBluetoothDevicesAvailableMediaDeviceUpdater
+ (fragment.getContext(), fragment, this, mGroupId);
+ }
+
+ @Override
+ public void onStart() {
+ mGroupDeviceUpdater.registerCallback();
+ }
+
+ @Override
+ public void onStop() {
+ mGroupDeviceUpdater.unregisterCallback();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ mPreferenceGroup = screen.findPreference(KEY);
+ mPreferenceGroup.setVisible(false);
+ if (isAvailable()) {
+ final Context context = screen.getContext();
+ mGroupDeviceUpdater.setPrefContext(context);
+ mGroupDeviceUpdater.forceUpdate();
+ }
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) ?
+ AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY;
+ }
+
+ @Override
+ public void onDeviceAdded(Preference preference) {
+ if (mPreferenceGroup.getPreferenceCount() == 0) {
+ mPreferenceGroup.setVisible(true);
+ }
+ mPreferenceGroup.addPreference(preference);
+ }
+
+ @Override
+ public void onDeviceRemoved(Preference preference) {
+ mPreferenceGroup.removePreference(preference);
+ if (mPreferenceGroup.getPreferenceCount() == 0) {
+ mPreferenceGroup.setVisible(false);
+ }
+ }
+
+}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothDevicesAvailableMediaDeviceUpdater.java b/src/com/android/settings/bluetooth/GroupBluetoothDevicesAvailableMediaDeviceUpdater.java
new file mode 100644
index 0000000000..770abac5a3
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothDevicesAvailableMediaDeviceUpdater.java
@@ -0,0 +1,117 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*****************************************************************************/
+package com.android.settings.bluetooth;
+
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.media.AudioManager;
+import android.util.Log;
+
+/**
+ * Controller to maintain available Group devices
+ */
+public class GroupBluetoothDevicesAvailableMediaDeviceUpdater extends
+ GroupBluetoothGroupDeviceUpdater {
+
+ private static final String TAG = "GroupBluetoothDevicesAvailableMediaDeviceUpdater";
+ private static final String PREF_KEY = "group_options_active_devices";
+ private int mGroupId;
+ private final AudioManager mAudioManager;
+ private GroupUtils mGroupUtils;
+
+ public GroupBluetoothDevicesAvailableMediaDeviceUpdater(Context context, DashboardFragment
+ fragment, DevicePreferenceCallback devicePreferenceCallback, int groupId) {
+ super(context, fragment, devicePreferenceCallback);
+ mGroupId = groupId;
+ mAudioManager = context.getSystemService(AudioManager.class);
+ mGroupUtils = new GroupUtils(context);
+ }
+
+ @Override
+ public void onAudioModeChanged() {
+ forceUpdate();
+ }
+
+ @Override
+ public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
+ final int audioMode = mAudioManager.getMode();
+ final int currentAudioProfile;
+ if (audioMode == AudioManager.MODE_RINGTONE || audioMode == AudioManager.MODE_IN_CALL
+ || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
+ // in phone call
+ currentAudioProfile = BluetoothProfile.HEADSET;
+ } else {
+ // without phone call
+ currentAudioProfile = BluetoothProfile.A2DP;
+ }
+ boolean isFilterMatched = false;
+ if (isDeviceConnected(cachedDevice)) {
+ if (DBG) {
+ Log.d(TAG, "isFilterMatched() current audio profile : " + currentAudioProfile);
+ }
+ // If device is Hearing Aid, it is compatible with HFP and A2DP.
+ // It would not show in Connected Devices group.
+ if (cachedDevice.isConnectedHearingAidDevice()) {
+ return false;
+ }
+ // According to the current audio profile type,
+ // this page will show the bluetooth device that doesn't have corresponding
+ // profile.
+ // For example:
+ // If current audio profile is a2dp,
+ // show the bluetooth device that doesn't have a2dp profile.
+ // If current audio profile is headset,
+ // show the bluetooth device that doesn't have headset profile.
+ switch (currentAudioProfile) {
+ case BluetoothProfile.A2DP:
+ isFilterMatched = cachedDevice.isConnectedA2dpDevice();
+ break;
+ case BluetoothProfile.HEADSET:
+ isFilterMatched = cachedDevice.isConnectedHfpDevice();
+ break;
+ }
+ if (DBG) {
+ Log.d(TAG, "isFilterMatched " + isFilterMatched
+ + " cachedDevice : " + cachedDevice );
+ }
+ }
+ return isFilterMatched && isGroupDevice(cachedDevice)
+ && mGroupId == mGroupUtils.getGroupId(cachedDevice);
+ }
+
+ @Override
+ protected String getPreferenceKey() {
+ return PREF_KEY;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothDevicesBondedController.java b/src/com/android/settings/bluetooth/GroupBluetoothDevicesBondedController.java
new file mode 100644
index 0000000000..f866ee0264
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothDevicesBondedController.java
@@ -0,0 +1,129 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+package com.android.settings.bluetooth;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import androidx.preference.PreferenceFragmentCompat;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+import com.android.settings.bluetooth.BluetoothDevicePreference;
+import com.android.settings.bluetooth.BluetoothDeviceUpdater;
+import com.android.settings.bluetooth.GroupSavedBluetoothDeviceUpdater;
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.connecteddevice.dock.DockUpdater;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.DockUpdaterFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.GearPreference;
+import com.android.settings.widget.GearPreference.OnGearClickListener;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+
+/**
+ * Maintain and update saved group devices(bonded but not connected)
+ */
+public class GroupBluetoothDevicesBondedController extends BasePreferenceController
+ implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop,
+ DevicePreferenceCallback {
+
+ private static final boolean DBG = ConnectedDeviceDashboardFragment.DBG_GROUP;
+ private static final String KEY = "group_options_bonded_devices";
+ private static final String TAG = "GroupBluetoothDevicesBondedController";
+ private PreferenceGroup mPreferenceGroup;
+ private GroupBluetoothDevicesBondedUpdater mGroupDeviceUpdater;
+ private int mGroupId;
+
+ public GroupBluetoothDevicesBondedController(Context context, DashboardFragment fragment,
+ Lifecycle lifecycle, int groupId) {
+ super(context, KEY);
+ mGroupId = groupId;
+ lifecycle.addObserver(this);
+ mGroupDeviceUpdater = new GroupBluetoothDevicesBondedUpdater(fragment.getContext(),
+ fragment, this, mGroupId);
+ }
+
+ @Override
+ public void onStart() {
+ mGroupDeviceUpdater.registerCallback();
+ }
+
+ @Override
+ public void onStop() {
+ mGroupDeviceUpdater.unregisterCallback();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ mPreferenceGroup = screen.findPreference(KEY);
+ mPreferenceGroup.setVisible(false);
+ if (isAvailable()) {
+ final Context context = screen.getContext();
+ mGroupDeviceUpdater.setPrefContext(context);
+ mGroupDeviceUpdater.forceUpdate();
+ }
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) ?
+ AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY;
+ }
+
+ @Override
+ public void onDeviceAdded(Preference preference) {
+ if (mPreferenceGroup.getPreferenceCount() == 0) {
+ mPreferenceGroup.setVisible(true);
+ }
+ mPreferenceGroup.addPreference(preference);
+ }
+
+ @Override
+ public void onDeviceRemoved(Preference preference) {
+ mPreferenceGroup.removePreference(preference);
+ if (mPreferenceGroup.getPreferenceCount() == 0) {
+ mPreferenceGroup.setVisible(false);
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothDevicesBondedUpdater.java b/src/com/android/settings/bluetooth/GroupBluetoothDevicesBondedUpdater.java
new file mode 100644
index 0000000000..5652fcf397
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothDevicesBondedUpdater.java
@@ -0,0 +1,92 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Maintain and update saved group devices(bonded but not connected)
+ */
+public class GroupBluetoothDevicesBondedUpdater extends GroupBluetoothDeviceUpdater
+ implements Preference.OnPreferenceClickListener {
+
+ private static final String TAG = "GroupBluetoothDevicesBondedUpdater";
+ private static final String PREF_KEY = "group_options_bonded_devices_updater";
+ private int mGroupId;
+ private GroupUtils mGroupUtils;
+
+ public GroupBluetoothDevicesBondedUpdater(Context context, DashboardFragment fragment,
+ DevicePreferenceCallback devicePreferenceCallback, int groupId) {
+ super(context, fragment, devicePreferenceCallback);
+ mGroupUtils = new GroupUtils(context);
+ mGroupId = groupId;
+ }
+
+ @Override
+ public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
+ final BluetoothDevice device = cachedDevice.getDevice();
+ int groupId = -1;
+ if (DBG) {
+ Log.d(TAG, "isFilterMatched " + cachedDevice + "bond state " + device.getBondState()
+ + " mGroupId " + mGroupId);
+ }
+ return (device.getBondState() == BluetoothDevice.BOND_BONDED)
+ && !device.isConnected() && isGroupDevice(cachedDevice)
+ && mGroupId == mGroupUtils.getGroupId(cachedDevice);
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ mMetricsFeatureProvider.logClickedPreference(preference, mFragment.getMetricsCategory());
+ final CachedBluetoothDevice device = ((BluetoothDevicePreference) preference)
+ .getBluetoothDevice();
+ device.connect();
+ return true;
+ }
+
+ @Override
+ protected String getPreferenceKey() {
+ return PREF_KEY;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothDevicesConnectedController.java b/src/com/android/settings/bluetooth/GroupBluetoothDevicesConnectedController.java
new file mode 100644
index 0000000000..cc3d89906d
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothDevicesConnectedController.java
@@ -0,0 +1,127 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.android.settings.bluetooth;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import androidx.preference.PreferenceFragmentCompat;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+import com.android.settings.bluetooth.BluetoothDevicePreference;
+import com.android.settings.bluetooth.BluetoothDeviceUpdater;
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.connecteddevice.dock.DockUpdater;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.DockUpdaterFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.GearPreference;
+import com.android.settings.widget.GearPreference.OnGearClickListener;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+
+/**
+ * Controller to maintain connected Group devices (Connected but not active)
+ */
+public class GroupBluetoothDevicesConnectedController extends BasePreferenceController
+ implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop,
+ DevicePreferenceCallback {
+
+ private static final String KEY = "group_options_connected_devices";
+ private static final String TAG = "GroupBluetoothDevicesConnectedController";
+ private PreferenceGroup mPreferenceGroup;
+ private GroupBluetoothDevicesConnectedUpdater mGroupDeviceUpdater;
+ private int mGroupId;
+
+ public GroupBluetoothDevicesConnectedController(Context context, DashboardFragment fragment,
+ Lifecycle lifecycle, int groupid) {
+ super(context, KEY);
+ mGroupId = groupid;
+ lifecycle.addObserver(this);
+ mGroupDeviceUpdater = new GroupBluetoothDevicesConnectedUpdater(fragment.getContext(),
+ fragment, this, mGroupId);
+ }
+
+ @Override
+ public void onStart() {
+ mGroupDeviceUpdater.registerCallback();
+ }
+
+ @Override
+ public void onStop() {
+ mGroupDeviceUpdater.unregisterCallback();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ mPreferenceGroup = screen.findPreference(KEY);
+ mPreferenceGroup.setVisible(false);
+ if (isAvailable()) {
+ final Context context = screen.getContext();
+ mGroupDeviceUpdater.setPrefContext(context);
+ mGroupDeviceUpdater.forceUpdate();
+ }
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return (mContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_BLUETOOTH)) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY;
+ }
+
+ @Override
+ public void onDeviceAdded(Preference preference) {
+ if (mPreferenceGroup.getPreferenceCount() == 0) {
+ mPreferenceGroup.setVisible(true);
+ }
+ mPreferenceGroup.addPreference(preference);
+ }
+
+ @Override
+ public void onDeviceRemoved(Preference preference) {
+ mPreferenceGroup.removePreference(preference);
+ if (mPreferenceGroup.getPreferenceCount() == 0) {
+ mPreferenceGroup.setVisible(false);
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothDevicesConnectedUpdater.java b/src/com/android/settings/bluetooth/GroupBluetoothDevicesConnectedUpdater.java
new file mode 100644
index 0000000000..1e28c9594b
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothDevicesConnectedUpdater.java
@@ -0,0 +1,135 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+package com.android.settings.bluetooth;
+
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+
+import androidx.preference.Preference;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.media.AudioManager;
+import android.util.Log;
+
+/**
+ * Controller to maintain connected ( not active) Group devices
+*/
+
+public class GroupBluetoothDevicesConnectedUpdater extends GroupBluetoothDeviceUpdater
+ implements Preference.OnPreferenceClickListener {
+
+ private static final String TAG = "GroupBluetoothDevicesConnectedUpdater";
+ private static final String PREF_KEY = "group_devices_connected";
+ private int mGroupId;
+ private final AudioManager mAudioManager;
+ private GroupUtils mGroupUtils;
+
+ public GroupBluetoothDevicesConnectedUpdater(Context context, DashboardFragment fragment,
+ DevicePreferenceCallback devicePreferenceCallback, int groupId) {
+ super(context, fragment, devicePreferenceCallback);
+ mGroupId = groupId;
+ mAudioManager = context.getSystemService(AudioManager.class);
+ mGroupUtils = new GroupUtils(context);
+ }
+
+ @Override
+ public void onAudioModeChanged() {
+ if (DBG) {
+ Log.d(TAG, "onAudioModeChanged ");
+ }
+ forceUpdate();
+ }
+
+ @Override
+ public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
+ final int audioMode = mAudioManager.getMode();
+ final int currentAudioProfile;
+ if (audioMode == AudioManager.MODE_RINGTONE || audioMode == AudioManager.MODE_IN_CALL
+ || audioMode == AudioManager.MODE_IN_COMMUNICATION) {
+ // in phone call
+ currentAudioProfile = BluetoothProfile.HEADSET;
+ } else {
+ // without phone call
+ currentAudioProfile = BluetoothProfile.A2DP;
+ }
+ boolean isFilterMatched = false;
+ if (isDeviceConnected(cachedDevice)) {
+ if (DBG) {
+ Log.d(TAG, "isFilterMatched() current audio profile : " + currentAudioProfile);
+ }
+ // If device is Hearing Aid, it is compatible with HFP and A2DP.
+ // It would not show in Connected Devices group.
+ if (cachedDevice.isConnectedHearingAidDevice()) {
+ return false;
+ }
+ // According to the current audio profile type,
+ // this page will show the bluetooth device that doesn't have corresponding
+ // profile.
+ // For example:
+ // If current audio profile is a2dp,
+ // show the bluetooth device that doesn't have a2dp profile.
+ // If current audio profile is headset,
+ // show the bluetooth device that doesn't have headset profile.
+ switch (currentAudioProfile) {
+ case BluetoothProfile.A2DP:
+ isFilterMatched = !cachedDevice.isConnectedA2dpDevice();
+ break;
+ case BluetoothProfile.HEADSET:
+ isFilterMatched = !cachedDevice.isConnectedHfpDevice();
+ break;
+ }
+ }
+ if (DBG) {
+ Log.d(TAG, "isFilterMatche cachedDevice : " + cachedDevice +" name "
+ + cachedDevice.getName() + ", isFilterMatched : " + isFilterMatched );
+ }
+
+ return isFilterMatched && isGroupDevice(cachedDevice)
+ && mGroupId == mGroupUtils.getGroupId(cachedDevice);
+ }
+
+ @Override
+ protected String getPreferenceKey() {
+ return PREF_KEY;
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ if (DBG) {
+ Log.d(TAG, "onPreferenceClick " + preference);
+ }
+ mMetricsFeatureProvider.logClickedPreference(preference, mFragment.getMetricsCategory());
+ final CachedBluetoothDevice device = ((BluetoothDevicePreference) preference)
+ .getBluetoothDevice();
+ return device.setActive();
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothFragment.java b/src/com/android/settings/bluetooth/GroupBluetoothFragment.java
new file mode 100644
index 0000000000..84033c4d60
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothFragment.java
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.android.settings.bluetooth;
+
+import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.android.settings.dashboard.RestrictedDashboardFragment;
+import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.instrumentation.Instrumentable;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.settings.R;
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
+
+/*
+ * Fragment to view Group related components
+*/
+public class GroupBluetoothFragment extends RestrictedDashboardFragment
+ implements BluetoothCallback {
+
+ private static final boolean DBG = ConnectedDeviceDashboardFragment.DBG_GROUP;
+ private static final String TAG = "GroupBluetoothFragment";
+ static final String KEY_GROUP_ID = "group_id";
+ private int mGroupId = -1;
+ private Context mCtx;
+ private GroupUtils mGroupUtils;
+ protected LocalBluetoothManager mLocalManager;
+
+ public GroupBluetoothFragment() {
+ super(DISALLOW_CONFIG_BLUETOOTH);
+ }
+
+ public static GroupBluetoothFragment newInstance(int groupId) {
+ Bundle args = new Bundle(1);
+ args.putInt(KEY_GROUP_ID, groupId);
+ GroupBluetoothFragment fragment = new GroupBluetoothFragment();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ mGroupId = getArguments().getInt(KEY_GROUP_ID);
+ mCtx = context;
+ mGroupUtils = new GroupUtils(mCtx);
+ mLocalManager = Utils.getLocalBtManager(mCtx);
+ mLocalManager.getEventManager().registerCallback(this);
+ super.onAttach(context);
+ if (mGroupId <= -1) {
+ // Close this page if groupId is not valid
+ Log.w(TAG, "onAttach mGroupId not valid " + mGroupId);
+ finish();
+ return;
+ }
+ use(GroupBluetoothDetailsButtonsController.class);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ finishFragmentIfNecessary();
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mLocalManager.getEventManager().unregisterCallback(this);
+ }
+
+ void finishFragmentIfNecessary() {
+ if (mGroupId < 0 || mGroupUtils.isHideGroupOptions(mGroupId)) {
+ Log.w(TAG, "finishFragment");
+ finish();
+ return;
+ }
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return Instrumentable.METRICS_CATEGORY_UNKNOWN;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.bluetooth_group_details_fragment;
+ }
+
+ @Override
+ protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+ if (DBG) {
+ Log.d(TAG, "createPreferenceControllers mGroupId " + mGroupId);
+ }
+ ArrayList<AbstractPreferenceController> controllers = new ArrayList<>();
+ Lifecycle lifecycle = getSettingsLifecycle();
+ controllers.add(new GroupBluetoothDetailsButtonsController(context,
+ this, mGroupId, lifecycle));
+ controllers.add(new GroupBluetoothDevicesAvailableMediaController(
+ context, this, lifecycle, mGroupId));
+ controllers.add(new GroupBluetoothDevicesConnectedController(
+ context, this, lifecycle, mGroupId));
+ controllers.add(new GroupBluetoothDevicesBondedController(
+ context, this, lifecycle, mGroupId));
+ return controllers;
+ }
+
+ @Override
+ public void onBluetoothStateChanged(int bluetoothState) {
+ if (DBG) {
+ Log.d(TAG, "onBluetoothStateChanged bluetoothState " + bluetoothState);
+ }
+ if (BluetoothAdapter.STATE_TURNING_OFF == bluetoothState) {
+ finish();
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothGroupDeviceUpdater.java b/src/com/android/settings/bluetooth/GroupBluetoothGroupDeviceUpdater.java
new file mode 100644
index 0000000000..9634d5bb20
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothGroupDeviceUpdater.java
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.GearPreference;
+import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.BluetoothDeviceFilter;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class GroupBluetoothGroupDeviceUpdater extends GroupBluetoothDeviceUpdater {
+
+ public GroupBluetoothGroupDeviceUpdater(Context context, DashboardFragment fragment,
+ DevicePreferenceCallback devicePreferenceCallback) {
+ super(context, fragment, devicePreferenceCallback);
+ }
+
+ @Override
+ protected void addPreference(CachedBluetoothDevice cachedDevice,
+ @BluetoothDevicePreference.SortType int type) {
+ final BluetoothDevice device = cachedDevice.getDevice();
+ if (!mPreferenceMap.containsKey(device)) {
+ BluetoothDevicePreference btPreference = new BluetoothDevicePreference(mPrefContext,
+ cachedDevice, true /* showDeviceWithoutNames */, type, true);
+ btPreference.setOnGearClickListener(mDeviceProfilesListener);
+ mPreferenceMap.put(device, btPreference);
+ mDevicePreferenceCallback.onDeviceAdded(btPreference);
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothProfileSwitchConfirmDialog.java b/src/com/android/settings/bluetooth/GroupBluetoothProfileSwitchConfirmDialog.java
new file mode 100644
index 0000000000..dd70b39ac3
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothProfileSwitchConfirmDialog.java
@@ -0,0 +1,129 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.android.settings.bluetooth;
+
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import android.util.Log;
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import com.android.settingslib.core.instrumentation.Instrumentable;
+
+import com.android.settings.R;
+import androidx.appcompat.app.AlertDialog;
+
+public class GroupBluetoothProfileSwitchConfirmDialog extends InstrumentedDialogFragment {
+
+ static final String TAG = "GroupBluetoothProfileSwitchConfirmDialog";
+ private static final String KEY_GROUP_ID ="group_id";
+ private int mGroupId = -1;
+ private GroupUtils mGroupUtils;
+ private BluetoothDetailsProfilesController mProfileController;
+
+ public interface BluetoothProfileConfirmListener {
+
+ void onDialogNegativeClick();
+
+ void onDialogPositiveClick();
+ }
+
+ public static GroupBluetoothProfileSwitchConfirmDialog newInstance(int groupId) {
+ Bundle args = new Bundle(1);
+ args.putInt(KEY_GROUP_ID, groupId);
+ GroupBluetoothProfileSwitchConfirmDialog dialog = new
+ GroupBluetoothProfileSwitchConfirmDialog();
+ dialog.setArguments(args);
+ return dialog;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return Instrumentable.METRICS_CATEGORY_UNKNOWN;
+ }
+
+ String getGroupTitle() {
+ mGroupId = getArguments().getInt(KEY_GROUP_ID);
+ return mGroupUtils.getGroupTitle(mGroupId);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle inState) {
+ DialogInterface.OnClickListener onConfirm = (dialog, which) -> {
+ onPositiveButtonClicked();
+ dialog.dismiss();
+ };
+ DialogInterface.OnClickListener onCancel = (dialog, which) -> {
+ onNegativeButtonClicked();
+ dialog.dismiss();
+ };
+
+ Context context = getContext();
+ mGroupUtils = new GroupUtils(context);
+ AlertDialog dialog = new AlertDialog.Builder(context)
+ .setPositiveButton(R.string.group_confirm_dialog_apply_button, onConfirm)
+ .setNegativeButton(android.R.string.cancel, onCancel).create();
+ dialog.setTitle(R.string.group_apply_changes_dialog_title);
+ dialog.setMessage(context.getString(R.string.group_confirm_dialog_body, getGroupTitle()));
+ return dialog;
+ }
+
+ /**
+ * Sets the controller that the fragment should use. this method MUST be called
+ * before you try to show the dialog or an error will be thrown. An implementation
+ * of a pairing controller can be found at {@link BluetoothPairingController}. A
+ * controller may not be substituted once it is assigned. Forcibly switching a
+ * controller for a new one will lead to undefined behavior.
+ */
+ void setPairingController(BluetoothDetailsProfilesController profileController) {
+ if (isPairingControllerSet()) {
+ throw new IllegalStateException("The controller can only be set once. "
+ + "Forcibly replacing it will lead to undefined behavior");
+ }
+ mProfileController = profileController;
+ }
+
+ /**
+ * Checks whether mPairingController is set
+ * @return True when mPairingController is set, False otherwise
+ */
+ boolean isPairingControllerSet() {
+ return mProfileController != null;
+ }
+
+ private void onPositiveButtonClicked() {
+ mProfileController.onDialogPositiveClick();
+ }
+
+ private void onNegativeButtonClicked() {
+ mProfileController.onDialogNegativeClick();
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupBluetoothSettingsPreference.java b/src/com/android/settings/bluetooth/GroupBluetoothSettingsPreference.java
new file mode 100644
index 0000000000..f55d6cfe69
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupBluetoothSettingsPreference.java
@@ -0,0 +1,166 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.android.settings.bluetooth;
+
+import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH;
+
+import com.android.settings.bluetooth.BluetoothDevicePreference.SortType;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.GearPreference;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.UserManager;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Pair;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.settings.R;
+
+
+public class GroupBluetoothSettingsPreference extends GearPreference {
+
+ private static final String TAG = "GroupBluetoothSettingsPreference";
+
+ private static int sDimAlpha = Integer.MIN_VALUE;
+
+ private int mGroupId = -1;
+
+ private final UserManager mUserManager;
+
+ private String contentDescription = null;
+ private boolean mHideSecondTarget = false;
+ private Resources mResources;
+ private int mVisibleCount = 0;
+
+ public GroupBluetoothSettingsPreference(Context context, int groupId) {
+ super(context, null);
+ mGroupId = groupId;
+ mResources = getContext().getResources();
+ mUserManager = context.getSystemService(UserManager.class);
+ if (sDimAlpha == Integer.MIN_VALUE) {
+ TypedValue outValue = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
+ sDimAlpha = (int) (outValue.getFloat() * 255);
+ }
+ mVisibleCount = 0;
+ onDeviceAttributesChanged();
+ }
+
+ @Override
+ protected boolean shouldHideSecondTarget() {
+ return mUserManager.hasUserRestriction(DISALLOW_CONFIG_BLUETOOTH)
+ || mHideSecondTarget;
+ }
+
+ public void hideSecondTarget(boolean hideSecondTarget) {
+ mHideSecondTarget = hideSecondTarget;
+ }
+
+ public void onDeviceAttributesChanged() {
+ /*
+ * The preference framework takes care of making sure the value has
+ * changed before proceeding. It will also call notifyChanged() if
+ * any preference info has changed from the previous value.
+ */
+ Context context = getContext();
+ String title = context.getString(R.string.group_settings);
+ setTitle(title + " " + (mGroupId + GroupUtils.GROUP_START_VAL));
+
+ // Used to gray out the item
+ setEnabled(true); // Change dynamically if required
+
+ setVisible(true); // Change to dynamic if required
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder view) {
+ // Disable this view if the bluetooth enable/disable preference view is off
+ if (null != findPreferenceInHierarchy("bt_checkbox")) {
+ setDependency("bt_checkbox");
+ }
+
+ ImageView deviceDetails = (ImageView) view.findViewById(R.id.settings_button);
+
+ if (deviceDetails != null) {
+ deviceDetails.setOnClickListener(this);
+ }
+ final ImageView imageView = (ImageView) view.findViewById(android.R.id.icon);
+ if (imageView != null) {
+ imageView.setContentDescription(contentDescription);
+ // Set property to prevent Talkback from reading out.
+ imageView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ imageView.setVisibility(ImageView.VISIBLE);
+ }
+ super.onBindViewHolder(view);
+ }
+
+
+ @Override
+ protected int getSecondTargetResId() {
+ return R.layout.preference_widget_gear;
+ }
+
+ public int getGroupId() {
+ return mGroupId;
+ }
+
+ void onClicked() {
+ }
+
+ public int getVisibleCount() {
+ return mVisibleCount;
+ }
+
+ public int incrementChildCound() {
+ return ++mVisibleCount;
+ }
+
+ public int decrementChildCount() {
+ return --mVisibleCount;
+ }
+
+ public boolean isRemovePref() {
+ if (mVisibleCount == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/GroupConnectedBluetoothDeviceUpdater.java
new file mode 100644
index 0000000000..d13946153c
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupConnectedBluetoothDeviceUpdater.java
@@ -0,0 +1,154 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.media.AudioManager;
+import android.util.Log;
+
+import androidx.preference.Preference;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+
+/**
+ * Controller to maintain connected devices based on group
+ */
+public class GroupConnectedBluetoothDeviceUpdater extends GroupBluetoothDeviceUpdater
+ implements Preference.OnPreferenceClickListener {
+
+ private static final String TAG = "GroupConnectedBluetoothDeviceUpdater";
+ private static final String PREF_KEY = "connected_group_bt";
+
+ public GroupConnectedBluetoothDeviceUpdater(Context context, DashboardFragment fragment,
+ DevicePreferenceCallback devicePreferenceCallback) {
+ super(context, fragment, devicePreferenceCallback);
+ }
+
+ @Override
+ public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
+ boolean isFilterMatched = isDeviceConnected(cachedDevice) && isGroupDevice(cachedDevice);
+ if (DBG) {
+ Log.d(TAG, "isFilterMatched cachedDevice " + cachedDevice.getName()
+ + " addr " + cachedDevice.getAddress() + " isConnected "
+ + isDeviceConnected(cachedDevice) + " isFilterMatched " + isFilterMatched);
+ }
+ return isFilterMatched;
+ }
+
+ /**
+ * Force to update the list of bluetooth devices
+ */
+ public void forceUpdate() {
+ if (mLocalManager == null) {
+ Log.e(TAG, "forceUpdate() Bluetooth is not supported on this device");
+ return;
+ }
+ final Collection<CachedBluetoothDevice> cachedDevices =
+ mLocalManager.getCachedDeviceManager().getCachedDevicesCopy();
+ final CachedBluetoothDeviceManager cachedManager =
+ mLocalManager.getCachedDeviceManager();
+ if (BluetoothAdapter.getDefaultAdapter().isEnabled()) {
+ for (CachedBluetoothDevice cachedBluetoothDevice : cachedDevices) {
+ update(cachedBluetoothDevice);
+ }
+ } else {
+ removeAllDevicesFromPreference();
+ removePreferenceIfNecessary(cachedDevices, cachedManager);
+ }
+ }
+
+ private void removePreferenceIfNecessary(Collection<CachedBluetoothDevice> bluetoothDevices,
+ CachedBluetoothDeviceManager cachedManager) {
+ for (BluetoothDevice device : new ArrayList<>(mPreferenceMap.keySet())) {
+ if (!bluetoothDevices.contains(device)) {
+ final CachedBluetoothDevice cachedDevice = cachedManager.findDevice(device);
+ if (cachedDevice != null) {
+ removePreference(cachedDevice);
+ } else if(cachedDevice == null) {
+ try {
+ BluetoothDevicePreference pref = (BluetoothDevicePreference)
+ mPreferenceMap.get(device);
+ final CachedBluetoothDevice cacDev = pref.getBluetoothDevice();
+ if (cacDev != null) {
+ removePreference(cacDev);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, " removePreferenceIfNecessary " + e);
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ protected String getPreferenceKey() {
+ return PREF_KEY;
+ }
+
+ @Override
+ protected void addPreference(CachedBluetoothDevice cachedDevice,
+ @BluetoothDevicePreference.SortType int type) {
+ final BluetoothDevice device = cachedDevice.getDevice();
+ if (!mPreferenceMap.containsKey(device)) {
+ final BluetoothDevicePreference btPreference =
+ new BluetoothDevicePreference(mPrefContext, cachedDevice,
+ true /* showDeviceWithoutNames */,
+ type, true /*hide summary */);
+ btPreference.setOnGearClickListener(mDeviceProfilesListener);
+ if (this instanceof Preference.OnPreferenceClickListener) {
+ btPreference.setOnPreferenceClickListener(
+ (Preference.OnPreferenceClickListener)this);
+ }
+ mPreferenceMap.put(device, btPreference);
+ mDevicePreferenceCallback.onDeviceAdded(btPreference);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ if (DBG) {
+ Log.d(TAG, " onPreferenceClick " + preference);
+ }
+ mMetricsFeatureProvider.logClickedPreference(preference, mFragment.getMetricsCategory());
+ final CachedBluetoothDevice device = ((BluetoothDevicePreference) preference)
+ .getBluetoothDevice();
+ return device.setActive();
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupForgetDialogFragment.java b/src/com/android/settings/bluetooth/GroupForgetDialogFragment.java
new file mode 100644
index 0000000000..da9c7cd3fc
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupForgetDialogFragment.java
@@ -0,0 +1,103 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.android.settings.bluetooth;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.util.Log;
+import androidx.appcompat.app.AlertDialog;
+
+import java.util.List;
+
+import com.android.settings.R;
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
+import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
+import com.android.settingslib.bluetooth.BluetoothUtils;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.core.instrumentation.Instrumentable;
+
+/** Implements an AlertDialog for confirming that a user wishes to unpair or "forget"
+* a Group of devices*/
+public class GroupForgetDialogFragment extends InstrumentedDialogFragment {
+
+ private static final boolean DBG = ConnectedDeviceDashboardFragment.DBG_GROUP;
+ protected static final String TAG = "GroupForgetDialogFragment";
+ private static final String KEY_GROUPID = "groupid";
+ private static List<CachedBluetoothDevice> mDevices ;
+ private int mGroupId;
+ private GroupUtils mGroupUtils;
+ public static GroupForgetDialogFragment newInstance(int groupId) {
+ Bundle args = new Bundle(1);
+ args.putInt(KEY_GROUPID, groupId);
+ GroupForgetDialogFragment dialog = new GroupForgetDialogFragment();
+ dialog.setArguments(args);
+ return dialog;
+ }
+
+ String getGroupTitle() {
+ mGroupId = getArguments().getInt(KEY_GROUPID);
+ return mGroupUtils.getGroupTitle(mGroupId);
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return Instrumentable.METRICS_CATEGORY_UNKNOWN;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle inState) {
+ DialogInterface.OnClickListener onConfirm = (dialog, which) -> {
+ forget();
+ Activity activity = getActivity();
+ if (activity != null) {
+ activity.finish();
+ }
+ };
+ Context context = getContext();
+ mGroupUtils = new GroupUtils(context);
+ AlertDialog dialog = new AlertDialog.Builder(context)
+ .setPositiveButton(R.string.groupaudio_unpair_dialog_forget_confirm_button,
+ onConfirm)
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ dialog.setTitle(R.string.groupaudio_unpair_dialog_title);
+ dialog.setMessage(context.getString(R.string.groupaudio_unpair_dialog_body,
+ getGroupTitle()));
+ return dialog;
+ }
+
+ private void forget() {
+ mGroupUtils.forgetGroup(mGroupId);
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupSavedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/GroupSavedBluetoothDeviceUpdater.java
new file mode 100644
index 0000000000..621675fb09
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupSavedBluetoothDeviceUpdater.java
@@ -0,0 +1,143 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.core.SubSettingLauncher;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.HashMap;
+
+/**
+ * Maintain and update saved Group devices(bonded but not connected)
+ */
+public class GroupSavedBluetoothDeviceUpdater extends GroupBluetoothDeviceUpdater
+ implements Preference.OnPreferenceClickListener {
+
+ private static final String TAG = "GroupSavedBluetoothDeviceUpdater";
+ private static final String PREF_KEY = "saved_group_bt";
+ private BluetoothAdapter mBluetoothAdapter;
+
+ public GroupSavedBluetoothDeviceUpdater(Context context, DashboardFragment fragment,
+ DevicePreferenceCallback devicePreferenceCallback) {
+ super(context, fragment, devicePreferenceCallback);
+ mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ }
+
+ @Override
+ public void forceUpdate() {
+ if (mBluetoothAdapter.isEnabled()) {
+ final CachedBluetoothDeviceManager cachedManager =
+ mLocalManager.getCachedDeviceManager();
+ final List<BluetoothDevice> bluetoothDevices =
+ mBluetoothAdapter.getMostRecentlyConnectedDevices();
+ removePreferenceIfNecessary(bluetoothDevices, cachedManager);
+ for(BluetoothDevice device : bluetoothDevices) {
+ final CachedBluetoothDevice cachedDevice = cachedManager.findDevice(device);
+ if (cachedDevice != null) {
+ update(cachedDevice);
+ }
+ }
+ } else {
+ removeAllDevicesFromPreference();
+ }
+ }
+
+ private void removePreferenceIfNecessary(List<BluetoothDevice> bluetoothDevices,
+ CachedBluetoothDeviceManager cachedManager) {
+ for (BluetoothDevice device : new ArrayList<>(mPreferenceMap.keySet())) {
+ if (!bluetoothDevices.contains(device)) {
+ final CachedBluetoothDevice cachedDevice = cachedManager.findDevice(device);
+ if (cachedDevice != null) {
+ removePreference(cachedDevice);
+ } else if(cachedDevice == null) {
+ try {
+ BluetoothDevicePreference pref = (BluetoothDevicePreference)
+ mPreferenceMap.get(device);
+ final CachedBluetoothDevice cacDev = pref.getBluetoothDevice();
+ if (cacDev != null) {
+ removePreference(cacDev);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "removePreferenceIfNecessary " + e);
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void update(CachedBluetoothDevice cachedDevice) {
+ if (isFilterMatched(cachedDevice)) {
+ addPreference(cachedDevice, BluetoothDevicePreference.SortType.TYPE_NO_SORT);
+ } else {
+ removePreference(cachedDevice);
+ }
+ }
+
+ @Override
+ public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
+ final BluetoothDevice device = cachedDevice.getDevice();
+ if (DBG) {
+ Log.d(TAG, " cachedDevice : " + cachedDevice + ", isConnected " + device.isConnected()
+ +" isBonded " + (device.getBondState() == BluetoothDevice.BOND_BONDED));
+ }
+ return (device.getBondState() == BluetoothDevice.BOND_BONDED)
+ && !device.isConnected() && isGroupDevice(cachedDevice);
+ }
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ mMetricsFeatureProvider.logClickedPreference(preference, mFragment.getMetricsCategory());
+ final CachedBluetoothDevice device = ((BluetoothDevicePreference) preference)
+ .getBluetoothDevice();
+ device.connect();
+ return true;
+ }
+
+ @Override
+ protected String getPreferenceKey() {
+ return PREF_KEY;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/GroupUtils.java b/src/com/android/settings/bluetooth/GroupUtils.java
new file mode 100644
index 0000000000..04d1a85901
--- /dev/null
+++ b/src/com/android/settings/bluetooth/GroupUtils.java
@@ -0,0 +1,669 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+package com.android.settings.bluetooth;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
+import com.android.settings.widget.GearPreference.OnGearClickListener;
+import com.android.settings.widget.GroupPreferenceCategory;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
+import com.android.settingslib.bluetooth.DeviceGroupClientProfile;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.bluetooth.LocalBluetoothProfile;
+import com.android.settings.R;
+
+import com.android.settings.core.SubSettingLauncher;
+import android.app.settings.SettingsEnums;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.DeviceGroup;
+import android.content.Context;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Log;
+import android.os.Bundle;
+
+/**
+ * GroupUtils is a helper class that contains various Group UI specific
+ * methods for add preference , remove preference, and group actions
+ */
+public class GroupUtils {
+
+ public static final String TAG_GROUP = "Group";
+ private static final String TAG = "GroupUtilss";
+ private static final boolean D = ConnectedDeviceDashboardFragment.DBG_GROUP;
+ private static final boolean V = Log.isLoggable(TAG, Log.VERBOSE);
+ private Context mCtx;
+ private CachedBluetoothDeviceManager mCacheDeviceNamanger;
+ private DeviceGroupClientProfile mGroupClientProfile;
+ private DeviceGroup mDeviceGroup;
+ private static final int INVALID_SIZE = 0;
+ private static final int INVALID_GROUPID = -1;
+ public static final int GROUP_START_VAL = 1;
+ private static final String PROPERTY_GROUP = "persist.vendor.service.bt.adv_audio_mask";
+ private boolean mIsGroupEnabled = false;
+
+ protected LocalBluetoothProfileManager mProfileManager;
+ private LocalBluetoothManager mLocalBluetoothManager;
+ private LocalBluetoothProfile mBCProfile = null;
+ private static final String KEY_DEVICE_ADDRESS = "device_address";
+ private static final String KEY_GROUP_OP = "group_op";
+ /*
+ * Returns whether if the device is group device.
+ */
+ boolean isGroupDevice(CachedBluetoothDevice cachedDevice) {
+ if (!mIsGroupEnabled) {
+ if (D) {
+ loge(" GroupProfile not enabled");
+ }
+ return false;
+ }
+ if (!cachedDevice.isGroupDevice()) {
+ if (cachedDevice.isTypeUnKnown()) {
+ int type = cachedDevice.getDevice().getDeviceType();
+ updateGroupStatus(cachedDevice, type);
+ }
+ }
+ if (D) {
+ Log.d(TAG, "isGroupDevice " + cachedDevice.isGroupDevice() + cachedDevice
+ + " name " + cachedDevice.getName() + " type " + cachedDevice.getmType());
+ }
+ return cachedDevice.isGroupDevice();
+ }
+
+ String getGroupTitle(int groupId) {
+ return " " + (groupId + GROUP_START_VAL);
+ }
+
+ /*
+ * Get group id associated with this device
+ */
+ int getGroupId(CachedBluetoothDevice device) {
+ int groupId = device.getGroupId();
+ if (groupId == -1) {
+ loge(" groupId is -1");
+ }
+ if (D) {
+ Log.d(TAG, "getgroupId " + groupId + " device " + device);
+ }
+ return groupId;
+ }
+
+ private void updateGroupStatus(CachedBluetoothDevice device, int groupId) {
+ device.setDeviceType(groupId);
+ CachedBluetoothDevice cacheDevice = mCacheDeviceNamanger.findDevice(device.getDevice());
+ if (cacheDevice != null) {
+ cacheDevice.setDeviceType(groupId);
+ if (D) {
+ Log.d(TAG, "updateGroupStatus updated " + device + " " + groupId);
+ }
+ } else {
+ loge("updateGroupStatus failed " + device + " groupId " + groupId);
+ }
+ }
+
+ public GroupUtils(Context ctx) {
+ mCtx = ctx;
+ mCacheDeviceNamanger = Utils.getLocalBtManager(mCtx).getCachedDeviceManager();
+ isGroupEnabled();
+ mLocalBluetoothManager = Utils.getLocalBtManager(mCtx);
+ if (mLocalBluetoothManager == null) {
+ Log.e(TAG, "Bluetooth is not supported on this device");
+ return;
+ }
+ mProfileManager = mLocalBluetoothManager.getProfileManager();
+ mBCProfile = mProfileManager.getBCProfile();
+ }
+
+ private int getGroupId(Preference preference) {
+ CachedBluetoothDevice dev = null;
+ int groupId = -1;
+ if (preference instanceof BluetoothDevicePreference) {
+ dev = ((BluetoothDevicePreference) preference).getBluetoothDevice();
+ groupId = getGroupId(dev);
+ }
+ if (groupId == -1) {
+ loge("group id not found " + dev.getAddress());
+ }
+ return groupId;
+ }
+
+ private boolean isNewGroup(int id, ArrayList< GroupPreferenceCategory> groupList) {
+ boolean isNew = true;
+ for (int i = 0; i< groupList.size() - 1; i++) {
+ GroupPreferenceCategory tempGroup = groupList.get(i);
+ if (tempGroup == null) {
+ loge("isNewGroup tempGroup null");
+ return false;
+ }
+ int val = tempGroup.getGroupId();
+ if (D) {
+ Log.d(TAG, "isNewGroup val " + val + " key " + tempGroup.getKey());
+ }
+ if (id == val) {
+ isNew = false;
+ break;
+ }
+ }
+ if (D) {
+ Log.d(TAG, "isNewGroup id " + id + " val " + isNew);
+ }
+ return isNew;
+ }
+
+ private boolean isAllFilled(int id, ArrayList< GroupPreferenceCategory> groupList) {
+ boolean filled = true;
+ for (int i = 0; i< groupList.size() - 1; i++) {
+ GroupPreferenceCategory tempGroup = groupList.get(i);
+ if (tempGroup == null) {
+ loge("isAllFilled");
+ return false;
+ }
+ int val = tempGroup.getGroupId();
+ if (id == val) {
+ filled = false;
+ break;
+ }
+ }
+ return filled;
+ }
+
+
+ private GroupPreferenceCategory getParentGroup(ArrayList< GroupPreferenceCategory> groupList,
+ Preference preference) {
+ GroupPreferenceCategory group = null;
+ for (int i = 0; i< groupList.size() - 1; i++) {
+ GroupPreferenceCategory tempGroup = groupList.get(i);
+ if (tempGroup.getPreferenceCount() == 0) {
+ group = tempGroup;
+ break;
+ }
+ }
+ return group;
+ }
+
+ private GroupPreferenceCategory getExistingGroup(ArrayList< GroupPreferenceCategory> mGroupList,
+ Preference preference) {
+ GroupPreferenceCategory group = null;
+ int groupId = getGroupId(preference);
+ for (GroupPreferenceCategory tempGroup : mGroupList) {
+ int val = tempGroup.getGroupId();
+ if (groupId == val) {
+ group = tempGroup;
+ break;
+ }
+ }
+ return group;
+ }
+
+ private GroupBluetoothSettingsPreference getHedaer(int groupId,
+ OnGearClickListener listener ) {
+ GroupBluetoothSettingsPreference headerPreference =
+ new GroupBluetoothSettingsPreference(mCtx, groupId);
+ headerPreference.setOnGearClickListener(listener);
+ return headerPreference;
+ }
+
+ /*
+ * Add preference based on below conditions
+ * a) Get group id based on Preference
+ * b) Check if already group header is present or not
+ * c) If new group create header
+ * d) Get available GroupPreferenceCategory instance
+ * e) Add Header and preference
+ * f) If group already present get group based on id
+ * g) Add preference to existing header
+ */
+ public void addPreference(ArrayList< GroupPreferenceCategory> listCategories,
+ Preference preference, OnGearClickListener listener) {
+ int groupId = getGroupId(preference);
+ if (groupId == -1) {
+ loge("addPreference groupId is not valid "+ groupId);
+ return;
+ }
+ boolean isNewGroup = isNewGroup(groupId, listCategories);
+ if (D) {
+ Log.d(TAG, "addPreference " + preference + " isNewGroup " + isNewGroup);
+ }
+ String key ;
+ GroupPreferenceCategory group = null;
+ if (isNewGroup) {
+ GroupBluetoothSettingsPreference header = getHedaer(groupId, listener);
+ group = getParentGroup(listCategories, preference);
+ if (group == null) {
+ loge("getParentGroup not found for groupId " + groupId);
+ isAllGroupsFilled(listCategories, header);
+ return;
+ }
+ group.setGroupId(groupId);
+ group.addPreference(header);
+ group.addPreference(preference);
+ group.setVisible(true);
+ } else {
+ group = getExistingGroup(listCategories, preference);
+ if (group == null) {
+ loge("getExistingGroup not found for groupId " + groupId);
+ return;
+ }
+ group.addPreference(preference);
+ }
+ if (D) {
+ Log.d(TAG , "addPreference key " + group.getKey());
+ }
+ }
+
+ /*
+ * Remove preference based on below conditions
+ * a) Get existing Preference Category
+ * b) Remove preference from category
+ * c) If preference count is one remove header
+ */
+ public void removePreference(ArrayList< GroupPreferenceCategory> listCategories,
+ Preference preference) {
+ GroupPreferenceCategory group = getExistingGroup(listCategories, preference);
+ if (group == null) {
+ loge("removePreference group null ");
+ removePreference(listCategories.get(listCategories.size()-1), preference);
+ return;
+ }
+ group.removePreference(preference);
+ if (group.getPreferenceCount() == 1) {
+ group.setGroupId(INVALID_GROUPID);
+ group.removeAll();
+ group.setVisible(false);
+ }
+ }
+
+ /*
+ * Remove Header if child count is 0
+ */
+ private void removePreference(GroupPreferenceCategory groupCategory,
+ Preference preference) {
+ int size = groupCategory.getPreferenceCount();
+ if (size == 0) {
+ loge("removePreference Header invalid");
+ return;
+ }
+ int groupId = getGroupId(preference);
+ if (groupId == INVALID_GROUPID) {
+ loge("removePreference Header groupId is invalid");
+ return;
+ }
+ for (int i=0;i<size; i++) {
+ GroupBluetoothSettingsPreference headerPreference =
+ (GroupBluetoothSettingsPreference) groupCategory.getPreference(i);
+ if (D) {
+ Log.d(TAG, "removePreference Header headerPreference "
+ + headerPreference + " header id "
+ + headerPreference.getGroupId() + " groupId " + groupId );
+ }
+ if (headerPreference.getGroupId() == groupId) {
+ int chCount = headerPreference.decrementChildCount();
+ if (D) {
+ Log.d(TAG,"removePreference Header group id chCount " + chCount );
+ }
+ if (chCount <= 0) {
+ groupCategory.removePreference(headerPreference);
+ }
+ }
+ }
+ }
+
+ /*
+ * If more than nine groups add headers only
+ */
+ private void isAllGroupsFilled(ArrayList<GroupPreferenceCategory> listCategories,
+ GroupBluetoothSettingsPreference preference) {
+ boolean isFilled = isAllFilled(-1, listCategories);
+ GroupPreferenceCategory group = listCategories.get(listCategories.size() - 1);
+ if (isFilled) {
+ if (group == null) {
+ loge("isAllGroupsFilled received invalid group");
+ return;
+ }
+ if (!group.getKey().contains("remaining")) {
+ loge("isAllGroupsFilled not last group");
+ return;
+ }
+ int size = group.getPreferenceCount();
+ if (D) {
+ Log.d(TAG, "isAllGroupsFilled size " + size);
+ }
+ boolean found = false;
+ for (int i = 0; i < size; i++) {
+ if (group.getPreference(i) instanceof GroupBluetoothSettingsPreference) {
+ GroupBluetoothSettingsPreference pref =
+ (GroupBluetoothSettingsPreference )group.getPreference(i);
+ if (preference.getGroupId() == pref.getGroupId()) {
+ found = true;
+ int chCount = pref.incrementChildCound();
+ if(D) {
+ Log.d(TAG, "isAllGroupsFilled updated chCount " + chCount);
+ }
+ break;
+ }
+ }
+ }
+ if (!found) {
+ int chCount = preference.incrementChildCound();
+ group.addPreference(preference);
+ if (D) {
+ Log.d(TAG, "isAllGroupsFilled added chCount " + chCount);
+ }
+ }
+ }
+ }
+
+ ArrayList<CachedBluetoothDevice> getCahcedDevice(int groupId) {
+ Collection<CachedBluetoothDevice> cachedDevices =
+ mCacheDeviceNamanger.getCachedDevicesCopy();
+ ArrayList<CachedBluetoothDevice> list = new ArrayList<CachedBluetoothDevice>();
+ for (CachedBluetoothDevice cachedDevice : cachedDevices) {
+ if (cachedDevice != null && isGroupDeviceBonded(cachedDevice)
+ && getGroupId(cachedDevice) == groupId) {
+ list.add(cachedDevice);
+ }
+ }
+ if (D) {
+ Log.d(TAG, "getCahcedDevice " + groupId + " list " + list + " " + list.size());
+ }
+ return list;
+ }
+
+ public BluetoothDevice getAnyBCConnectedDevice (int groupId) {
+ BluetoothDevice bcMemberDevice = null;
+
+ mDeviceGroup = mGroupClientProfile.getGroup(groupId);
+ if (mDeviceGroup == null) {
+ Log.e(TAG, "getAnyBCConnectedDevice: dGrp is null");
+ return null;
+ }
+ if (mBCProfile == null) {
+ Log.e(TAG, "getAnyBCConnectedDevice: BCProfile is null");
+ return null;
+ }
+ List<BluetoothDevice> setMembers = mDeviceGroup.getDeviceGroupMembers();
+ for (BluetoothDevice dev : setMembers) {
+ if (mBCProfile.getConnectionStatus(dev) == BluetoothProfile.STATE_CONNECTED) {
+ bcMemberDevice = dev;
+ break;
+ }
+ }
+ return bcMemberDevice;
+ }
+ void launchAddSourceGroup(int groupId) {
+ Class<?> SADetail = null;
+ try {
+ SADetail = Class.forName("com.android.settings.bluetooth.BluetoothSADetail");
+ } catch (ClassNotFoundException ex) {
+ Log.e(TAG, "no SADetail exists");
+ SADetail = null;
+ }
+ if (SADetail != null) {
+ BluetoothDevice bcMemberDevice = getAnyBCConnectedDevice(groupId);
+ final Bundle args = new Bundle();
+ if (bcMemberDevice == null) {
+ //do nothing
+ return;
+ }
+ args.putString(KEY_DEVICE_ADDRESS,
+ bcMemberDevice.getAddress());
+ args.putShort(KEY_GROUP_OP,
+ (short)1);
+
+ new SubSettingLauncher(mCtx)
+ .setDestination("com.android.settings.bluetooth.BluetoothSADetail")
+ .setArguments(args)
+ .setTitleRes(R.string.bluetooth_search_broadcasters)
+ .setSourceMetricsCategory(SettingsEnums.BLUETOOTH_DEVICE_PICKER)
+ .launch();
+ }
+ return;
+ }
+
+ boolean connectGroup(int groupId) {
+ if (isValid()) {
+ return mGroupClientProfile.connectGroup(groupId);
+ }
+ return false;
+ }
+
+ boolean disconnectGroup(int groupId) {
+ if (isValid()) {
+ return mGroupClientProfile.disconnectGroup(groupId);
+ }
+ return false;
+ }
+
+ boolean forgetGroup(int groupId) {
+ if (isValid()) {
+ return mGroupClientProfile.forgetGroup(groupId);
+ }
+ return false;
+ }
+
+ boolean isGroupDiscoveryInProgress(int groupId) {
+ if (!isValid()) {
+ return false;
+ }
+ return mGroupClientProfile.isGroupDiscoveryInProgress(groupId);
+ }
+
+ boolean startGroupDiscovery(int groupId) {
+ if (!isValid()) {
+ return false;
+ }
+ boolean isDiscovering= mGroupClientProfile.isGroupDiscoveryInProgress(groupId);
+ if (D) {
+ Log.d(TAG, "startGroupDiscovery " + groupId + "isDiscovering " + isDiscovering);
+ }
+ if (!isDiscovering) {
+ mGroupClientProfile.startGroupDiscovery(groupId);
+ return true;
+ }
+ return false;
+ }
+
+ boolean stopGroupDiscovery(int groupId) {
+ if (!isValid()) {
+ return false;
+ }
+ boolean isDiscovering = mGroupClientProfile.isGroupDiscoveryInProgress(groupId);
+ if (D) {
+ Log.d(TAG, "stopGroupDiscovery " + groupId + "isDiscovering " + isDiscovering);
+ }
+ if (isDiscovering) {
+ mGroupClientProfile.stopGroupDiscovery(groupId);
+ return true;
+ }
+ return false;
+ }
+
+ int getGroupSize(int groupId) {
+ int size = INVALID_SIZE;
+ if (isValid()) {
+ mDeviceGroup = mGroupClientProfile.getGroup(groupId);
+ if (mDeviceGroup != null) {
+ size = mDeviceGroup.getDeviceGroupSize();
+ }
+ }
+ if (D) {
+ Log.d(TAG, "getDeviceGroupSize size " + size);
+ }
+ return size;
+ }
+
+ public boolean isHidePCGGroups() {
+ boolean isHide = true;
+ List<BluetoothDevice> bluetoothDevices =
+ BluetoothAdapter.getDefaultAdapter().getMostRecentlyConnectedDevices();
+ if (bluetoothDevices != null && bluetoothDevices.size() > 0) {
+ for (BluetoothDevice device : bluetoothDevices) {
+ CachedBluetoothDevice cachedDevice = mCacheDeviceNamanger.findDevice(device);
+ if (cachedDevice != null && isGroupDeviceBondedOnly(cachedDevice)) {
+ isHide = false;
+ break;
+ }
+ }
+ }
+ if (D) {
+ Log.d(TAG, "isHidePCGGroups " + isHide);
+ }
+ return isHide;
+ }
+
+ boolean isHideGroupOptions(int groupId) {
+ boolean isHide = true;
+ Collection<CachedBluetoothDevice> cachedDevices =
+ mCacheDeviceNamanger.getCachedDevicesCopy();
+ if (cachedDevices != null && cachedDevices.size() > 0) {
+ for (CachedBluetoothDevice cachedDevice : cachedDevices) {
+ if (cachedDevice != null && isGroupDeviceBonded(cachedDevice)
+ && isGroupIdMatch(cachedDevice, groupId)) {
+ isHide = false;
+ break;
+ }
+ }
+ }
+ if (D) {
+ Log.d(TAG, "isHideGroupOptions " + isHide);
+ }
+ return isHide;
+ }
+
+ private boolean isGroupDeviceBondedOnly(CachedBluetoothDevice cachedDevice) {
+ if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
+ && !cachedDevice.isConnected() && isGroupDevice(cachedDevice)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private boolean isGroupIdMatch(CachedBluetoothDevice cachedDevice, int groupId) {
+ return groupId == getGroupId(cachedDevice);
+ }
+
+ private boolean isGroupDeviceBonded(CachedBluetoothDevice cachedDevice) {
+ if (cachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
+ && isGroupDevice(cachedDevice)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private void loge(String msg) {
+ Log.e(TAG, msg);
+ }
+
+ private boolean isValid() {
+ if (mGroupClientProfile == null) {
+ LocalBluetoothProfileManager profilemanager =
+ Utils.getLocalBtManager(mCtx).getProfileManager();
+ mGroupClientProfile = profilemanager.getDeviceGroupClientProfile();
+ }
+ return (mGroupClientProfile == null) ? false : true;
+ }
+
+ private void isGroupEnabled() {
+ try {
+ int advAudioFeatureMask = SystemProperties.getInt(PROPERTY_GROUP, 0);
+ if (D) {
+ Log.d(TAG,"isGroupEnabled advAudioFeatureMask " + advAudioFeatureMask);
+ }
+ if (advAudioFeatureMask != 0) {
+ mIsGroupEnabled = true;
+ }
+ } catch (Exception e) {
+ mIsGroupEnabled = false;
+ Log.e(TAG, "isGroupEnabled " + e);
+ }
+ }
+
+ boolean isUpdate(int groupId, CachedBluetoothDevice cachedDevice) {
+ return (isGroupDevice(cachedDevice) && groupId == getGroupId(cachedDevice));
+ }
+
+ boolean addDevice(ArrayList<CachedBluetoothDevice> deviceList, int groupId,
+ CachedBluetoothDevice cachedDevice) {
+ boolean add = true;
+ boolean isAdded = false;
+ if (isUpdate(groupId, cachedDevice)) {
+ for (CachedBluetoothDevice device : deviceList) {
+ if (device.getAddress().equals(cachedDevice.getAddress())) {
+ add = false;
+ break;
+ }
+ }
+ if (add) {
+ isAdded = deviceList.add(cachedDevice);
+ }
+ }
+ if (D) {
+ Log.d(TAG, "addDevice cachedDevice " + cachedDevice + " name " +
+ cachedDevice.getName() + " is added " + isAdded);
+ }
+ return add;
+ }
+
+ boolean removeDevice(ArrayList<CachedBluetoothDevice> deviceList, int groupId,
+ CachedBluetoothDevice cachedDevice) {
+ boolean remove = false;
+ boolean isremoved = false;
+ CachedBluetoothDevice removedDevice = null ;
+ if (isUpdate(groupId, cachedDevice)) {
+ for (CachedBluetoothDevice device : deviceList) {
+ if (device.getAddress().equals(cachedDevice.getAddress())) {
+ remove = true;
+ removedDevice = device;
+ break;
+ }
+ }
+ if (remove) {
+ isremoved = deviceList.remove(removedDevice);
+ }
+ }
+ if (D) {
+ Log.d(TAG, "removeDevice cachedDevice " + cachedDevice + " name " +
+ cachedDevice.getName() + " isremoved " + isremoved);
+ }
+ return remove;
+ }
+}
diff --git a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
index dab4f231e3..a4e7e334f9 100644
--- a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
@@ -1,4 +1,37 @@
/*
+ *Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -102,10 +135,13 @@ public class SavedBluetoothDeviceUpdater extends BluetoothDeviceUpdater
if (DBG) {
Log.d(TAG, "isFilterMatched() device name : " + cachedDevice.getName() +
", is connected : " + device.isConnected() + ", is profile connected : "
- + cachedDevice.isConnected());
+ + cachedDevice.isConnected() +
+ ", is twsplusdevice : " + device.isTwsPlusDevice());
}
return device.getBondState() == BluetoothDevice.BOND_BONDED
- && (mDisplayConnected || !device.isConnected());
+ && (mDisplayConnected || !device.isConnected())
+ && !device.isTwsPlusDevice() && !isGroupDevice(cachedDevice)
+ && !isPrivateAddr(cachedDevice);
}
@Override
diff --git a/src/com/android/settings/bluetooth/SavedBluetoothTwsDeviceUpdater.java b/src/com/android/settings/bluetooth/SavedBluetoothTwsDeviceUpdater.java
new file mode 100644
index 0000000000..eae4c5b56b
--- /dev/null
+++ b/src/com/android/settings/bluetooth/SavedBluetoothTwsDeviceUpdater.java
@@ -0,0 +1,91 @@
+/*
+ *Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settings.connecteddevice.DevicePreferenceCallback;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+
+/**
+ * Maintain and update saved TWS+ bluetooth devices(bonded but not connected)
+ */
+public class SavedBluetoothTwsDeviceUpdater extends BluetoothDeviceUpdater {
+
+ private static final String PREF_KEY = "saved_bt_tws";
+
+ public SavedBluetoothTwsDeviceUpdater(Context context, DashboardFragment fragment,
+ DevicePreferenceCallback devicePreferenceCallback) {
+ super(context, fragment, devicePreferenceCallback);
+ }
+
+ SavedBluetoothTwsDeviceUpdater(Context context, DashboardFragment fragment,
+ DevicePreferenceCallback devicePreferenceCallback,
+ LocalBluetoothManager localBluetoothManager) {
+ super(context, fragment, devicePreferenceCallback, localBluetoothManager);
+ }
+
+ @Override
+ public boolean isFilterMatched(CachedBluetoothDevice cachedDevice) {
+ final BluetoothDevice device = cachedDevice.getDevice();
+ return device.getBondState() == BluetoothDevice.BOND_BONDED &&
+ !device.isConnected() && device.isTwsPlusDevice() && !isGroupDevice(cachedDevice)
+ && !isPrivateAddr(cachedDevice);
+ }
+
+ @Override
+ protected String getPreferenceKey() {
+ return PREF_KEY;
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java b/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java
index 4591b7f216..9e86fa62ec 100644
--- a/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/BluetoothDashboardFragment.java
@@ -19,6 +19,11 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
+import android.os.SystemProperties;
+import android.util.Log;
+import android.view.View;
+import androidx.fragment.app.Fragment;
+import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.bluetooth.BluetoothDeviceRenamePreferenceController;
@@ -28,8 +33,13 @@ import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.widget.MainSwitchBarController;
import com.android.settings.widget.SettingsMainSwitchBar;
import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.widget.FooterPreference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
/**
* Dedicated screen for allowing the user to toggle bluetooth which displays relevant information to
@@ -40,6 +50,12 @@ public class BluetoothDashboardFragment extends DashboardFragment {
private static final String TAG = "BluetoothDashboardFrag";
private static final String KEY_BLUETOOTH_SCREEN_FOOTER = "bluetooth_screen_footer";
+ private static final String BLUETOOTH_ADV_AUDIO_MASK_PROP
+ = "persist.vendor.service.bt.adv_audio_mask";
+ private static final String BLUETOOTH_BROADCAST_UI_PROP = "persist.bluetooth.broadcast_ui";
+ private static final int BROADCAST_MASK = 0x04;
+ private static boolean mBroadcastEnabled = false;
+ private static boolean mBroadcastPropertyChecked = false;
private FooterPreference mFooterPreference;
private SettingsMainSwitchBar mSwitchBar;
@@ -78,6 +94,59 @@ public class BluetoothDashboardFragment extends DashboardFragment {
}
@Override
+ protected void displayResourceTilesToScreen(PreferenceScreen screen) {
+ if (mBroadcastEnabled == false) {
+ screen.removePreference(screen.findPreference("bluetooth_screen_broadcast_enable"));
+ screen.removePreference(
+ screen.findPreference("bluetooth_screen_broadcast_pin_configure"));
+ }
+ super.displayResourceTilesToScreen(screen);
+ }
+
+ @Override
+ protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+ List<AbstractPreferenceController> controllers = new ArrayList<>();
+ if (mBroadcastPropertyChecked == false) {
+ int advAudioMask = SystemProperties.getInt(BLUETOOTH_ADV_AUDIO_MASK_PROP, 0);
+ mBroadcastEnabled = (((advAudioMask & BROADCAST_MASK) == BROADCAST_MASK) &&
+ SystemProperties.getBoolean(BLUETOOTH_BROADCAST_UI_PROP, true));
+ mBroadcastPropertyChecked = true;
+ }
+
+ if (mBroadcastEnabled == false) {
+ return controllers;
+ }
+
+ Log.d (TAG, "createPreferenceControllers for Broadcast");
+
+ try {
+ Class<?> classBroadcastPinController =
+ Class.forName("com.android.settings.bluetooth.BluetoothBroadcastPinController");
+ Class<?> classBroadcastEnableController =
+ Class.forName("com.android.settings.bluetooth.BluetoothBroadcastEnableController");
+ Constructor ctorPin, ctorEnable;
+ ctorPin = classBroadcastPinController
+ .getDeclaredConstructor(new Class[] {Context.class, Lifecycle.class});
+ ctorEnable = classBroadcastEnableController
+ .getDeclaredConstructor(new Class[] {Context.class, String.class, Lifecycle.class});
+ Object objBroadcastPinController = ctorPin.newInstance(context, getSettingsLifecycle());
+ Object objBroadcastEnableController = ctorEnable
+ .newInstance(context, new String("bluetooth_screen_broadcast_enable"), getSettingsLifecycle());
+ objBroadcastPinController.getClass().getMethod("setFragment", Fragment.class)
+ .invoke(objBroadcastPinController, (Fragment) this);
+ controllers.add((AbstractPreferenceController) objBroadcastPinController);
+ controllers.add((AbstractPreferenceController) objBroadcastEnableController);
+ } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
+ InvocationTargetException | InstantiationException | IllegalArgumentException |
+ ExceptionInInitializerError e) {
+ mBroadcastEnabled = false;
+ e.printStackTrace();
+ } finally {
+ return controllers;
+ }
+ }
+
+ @Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
diff --git a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
index c8eb488df0..3fcc136fab 100644
--- a/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
+++ b/src/com/android/settings/connecteddevice/ConnectedDeviceDashboardFragment.java
@@ -1,4 +1,37 @@
/*
+ *Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,10 +65,15 @@ import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.slices.SlicePreferenceController;
import com.android.settingslib.search.SearchIndexable;
+import android.util.Log;
+
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class ConnectedDeviceDashboardFragment extends DashboardFragment {
private static final String TAG = "ConnectedDeviceFrag";
+ private static final String TAG_GROUP = "Group";
+
+ public static final boolean DBG_GROUP = Log.isLoggable(TAG_GROUP, Log.DEBUG);
private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
private static final String SYSTEMUI_PACKAGE_NAME = "com.android.systemui";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -77,7 +115,10 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
}
use(AvailableMediaDeviceGroupController.class).init(this);
use(ConnectedDeviceGroupController.class).init(this);
+ use(SavedTwsDeviceGroupController.class).init(this);
use(PreviouslyConnectedDevicePreferenceController.class).init(this);
+ use(GroupConnectedBluetoothDevicesController.class).init(this);
+ use(GroupPreviouslyConnectedDevicePreferenceController.class).init(this);
use(SlicePreferenceController.class).setSliceUri(nearbyEnabled
? Uri.parse(getString(R.string.config_nearby_devices_slice_uri))
: null);
diff --git a/src/com/android/settings/connecteddevice/GroupConnectedBluetoothDevicesController.java b/src/com/android/settings/connecteddevice/GroupConnectedBluetoothDevicesController.java
new file mode 100644
index 0000000000..8ef95f0b88
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/GroupConnectedBluetoothDevicesController.java
@@ -0,0 +1,174 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+package com.android.settings.connecteddevice;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.bluetooth.BluetoothDeviceUpdater;
+import com.android.settings.bluetooth.GroupBluetoothSettingsPreference;
+import com.android.settings.bluetooth.ConnectedBluetoothDeviceUpdater;
+import com.android.settings.bluetooth.GroupConnectedBluetoothDeviceUpdater;
+import com.android.settings.bluetooth.GroupUtils;
+import com.android.settings.connecteddevice.dock.DockUpdater;
+import com.android.settings.connecteddevice.usb.ConnectedUsbDeviceUpdater;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.DockUpdaterFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.GearPreference;
+import com.android.settings.widget.GearPreference.OnGearClickListener;
+import com.android.settings.widget.GroupPreferenceCategory;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+import java.util.ArrayList;
+
+import com.android.settings.R;
+
+/**
+ * Controller to maintain for all connected Group devices.
+ * It uses {@link DevicePreferenceCallback} to add/remove {@link Preference}
+ */
+public class GroupConnectedBluetoothDevicesController extends BasePreferenceController
+ implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop,
+ DevicePreferenceCallback, OnGearClickListener {
+
+ private static final String TAG = "GroupConnectedBluetoothDevicesController";
+ private static final String KEY_ONE = "group_one";
+ private static final String KEY_TWO = "group_two";
+ private static final String KEY_THREE = "group_three";
+ private static final String KEY_FOUR = "group_four";
+ private static final String KEY_FIVE = "group_five";
+ private static final String KEY_SIX = "group_six";
+ private static final String KEY_SEVEN = "group_seven";
+ private static final String KEY_EIGHT = "group_eight";
+ private static final String KEY_NINE = "group_nine";
+ private static final String KEY_REMAINING = "group_remaining";
+ private static final String KEY_GROUP = "group_connected_device_list";
+ private GroupBluetoothSettingsPreference mGroupSettings;
+ private PreferenceGroup mPreferenceGroup;
+ private GroupConnectedBluetoothDeviceUpdater mBluetoothDeviceUpdater;
+ private Preference mPreferenceSeeAll;
+ private GroupPreferenceCategory mPreferenceGroupOne, mPreferenceGroupTwo, mPreferenceGroupThree,
+ mPreferenceGroupFour, mPreferenceGroupFive, mPreferenceGroupSix, mPreferenceGroupSeven,
+ mPreferenceGroupEight, mPreferenceGroupNine,mPreferenceGroupRemaining;
+ private ArrayList< GroupPreferenceCategory> mGroupList =
+ new ArrayList<GroupPreferenceCategory>();
+ private GroupUtils mGroupUtils;
+ private Context mPerfCtx;
+
+ public GroupConnectedBluetoothDevicesController(Context context) {
+ super(context, KEY_ONE);
+ }
+
+ @Override
+ public void onStart() {
+ mBluetoothDeviceUpdater.registerCallback();
+ }
+
+ @Override
+ public void onStop() {
+ mBluetoothDeviceUpdater.unregisterCallback();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreferenceGroup = screen.findPreference(KEY_GROUP);
+ mPreferenceGroupOne = screen.findPreference(KEY_ONE);
+ mPreferenceGroupTwo = screen.findPreference(KEY_TWO);
+ mPreferenceGroupThree = screen.findPreference(KEY_THREE);
+ mPreferenceGroupFour = screen.findPreference(KEY_FOUR);
+ mPreferenceGroupFive = screen.findPreference(KEY_FIVE);
+ mPreferenceGroupSix = screen.findPreference(KEY_SIX);
+ mPreferenceGroupSeven = screen.findPreference(KEY_SEVEN);
+ mPreferenceGroupEight= screen.findPreference(KEY_EIGHT);
+ mPreferenceGroupNine = screen.findPreference(KEY_NINE);
+ mPreferenceGroupRemaining = screen.findPreference(KEY_REMAINING);
+ mGroupList.add(mPreferenceGroupOne);
+ mGroupList.add(mPreferenceGroupTwo);
+ mGroupList.add(mPreferenceGroupThree);
+ mGroupList.add(mPreferenceGroupFour);
+ mGroupList.add(mPreferenceGroupFive);
+ mGroupList.add(mPreferenceGroupSix);
+ mGroupList.add(mPreferenceGroupSeven);
+ mGroupList.add(mPreferenceGroupEight);
+ mGroupList.add(mPreferenceGroupNine);
+ mGroupList.add(mPreferenceGroupRemaining);
+
+ if (isAvailable()) {
+ final Context context = screen.getContext();
+ mGroupUtils = new GroupUtils(context);
+ mBluetoothDeviceUpdater.setPrefContext(context);
+ mBluetoothDeviceUpdater.forceUpdate();
+ }
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ final PackageManager packageManager = mContext.getPackageManager();
+ return (packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH))
+ ? AVAILABLE_UNSEARCHABLE
+ : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_ONE;
+ }
+
+ @Override
+ public void onDeviceAdded(Preference preference) {
+ mGroupUtils.addPreference(mGroupList, preference, this);
+ }
+
+ @Override
+ public void onDeviceRemoved(Preference preference) {
+ mGroupUtils.removePreference(mGroupList, preference);
+ }
+
+ public void init(DashboardFragment fragment) {
+ mBluetoothDeviceUpdater = new GroupConnectedBluetoothDeviceUpdater(fragment.getContext(),
+ fragment, GroupConnectedBluetoothDevicesController.this);
+ }
+
+ @Override
+ public void onGearClick(GearPreference p) {
+ GroupBluetoothSettingsPreference pre =(GroupBluetoothSettingsPreference)p;
+ mBluetoothDeviceUpdater.launchgroupOptions(pre);
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/GroupPreviouslyConnectedDeviceDashboardFragment.java b/src/com/android/settings/connecteddevice/GroupPreviouslyConnectedDeviceDashboardFragment.java
new file mode 100644
index 0000000000..9c639c4580
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/GroupPreviouslyConnectedDeviceDashboardFragment.java
@@ -0,0 +1,87 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+package com.android.settings.connecteddevice;
+
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.bluetooth.GroupUtils;
+import com.android.settings.dashboard.DashboardFragment;
+import android.util.Log;
+import com.android.settingslib.core.instrumentation.Instrumentable;
+
+import java.security.spec.MGF1ParameterSpec;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * This fragment contains previously connected Group devices
+ */
+public class GroupPreviouslyConnectedDeviceDashboardFragment extends DashboardFragment {
+
+ private static final String TAG = "GroupPreviouslyConnectedDeviceDashboardFragment";
+ static final String KEY_PREVIOUSLY_CONNECTED_GROUP_DEVICES = "group_saved_device_list";
+ private GroupUtils mGroupUtils;
+
+ @Override
+ public int getHelpResource() {
+ return R.string.group_help_url_previously_connected_devices;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.previously_connected_group_devices;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return Instrumentable.METRICS_CATEGORY_UNKNOWN;
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mGroupUtils = new GroupUtils(context);
+ use(GroupSavedDeviceController.class).init(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mGroupUtils.isHidePCGGroups()) {
+ finish();
+ }
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/GroupPreviouslyConnectedDevicePreferenceController.java b/src/com/android/settings/connecteddevice/GroupPreviouslyConnectedDevicePreferenceController.java
new file mode 100644
index 0000000000..0b7d6706af
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/GroupPreviouslyConnectedDevicePreferenceController.java
@@ -0,0 +1,148 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+package com.android.settings.connecteddevice;
+
+import android.bluetooth.BluetoothAdapter;
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.bluetooth.BluetoothDeviceUpdater;
+import com.android.settings.bluetooth.GroupSavedBluetoothDeviceUpdater;
+import com.android.settings.bluetooth.Utils;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.connecteddevice.dock.DockUpdater;
+import com.android.settings.overlay.FeatureFactory;
+
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+import android.util.Log;
+
+/**
+ * Controller to maintain the {@link PreferenceGroup} for saved group devices.
+ * It uses {@link DevicePreferenceCallback} to add/remove {@link Preference}
+ */
+public class GroupPreviouslyConnectedDevicePreferenceController extends BasePreferenceController
+ implements LifecycleObserver, OnStart, OnStop, DevicePreferenceCallback, BluetoothCallback {
+
+ private static final String TAG = "GroupPreviouslyConnectedDevicePreferenceController";
+ private PreferenceGroup mPreferenceGroup;
+ private GroupSavedBluetoothDeviceUpdater mBluetoothDeviceUpdater;
+ private int mPreferenceSize;
+ private static final int MAX_DEVICE_NUM = 3;
+ private DockUpdater mSavedDockUpdater;
+ private LocalBluetoothAdapter mLocalAdapter;
+ private LocalBluetoothManager manager;
+
+
+ public GroupPreviouslyConnectedDevicePreferenceController(Context context,
+ String preferenceKey) {
+ super(context, preferenceKey);
+ mSavedDockUpdater = FeatureFactory.getFactory(context).
+ getDockUpdaterFeatureProvider().getSavedDockUpdater(context, this);
+ manager = Utils.getLocalBtManager(context);
+ if ( manager != null) {
+ mLocalAdapter = manager.getBluetoothAdapter();
+ }
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
+ )
+ ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreferenceGroup = screen.findPreference(getPreferenceKey());
+ mPreferenceGroup.setVisible(false);
+ if (isAvailable()) {
+ final Context context = screen.getContext();
+ mBluetoothDeviceUpdater.setPrefContext(context);
+ mSavedDockUpdater.setPreferenceContext(context);
+ }
+ }
+
+ @Override
+ public void onStart() {
+ mBluetoothDeviceUpdater.registerCallback();
+ mSavedDockUpdater.registerCallback();
+ }
+
+ @Override
+ public void onStop() {
+ mBluetoothDeviceUpdater.unregisterCallback();
+ mSavedDockUpdater.unregisterCallback();
+ }
+
+ public void init(DashboardFragment fragment) {
+ mBluetoothDeviceUpdater = new GroupSavedBluetoothDeviceUpdater(fragment.getContext(),
+ fragment, GroupPreviouslyConnectedDevicePreferenceController.this);
+ }
+
+ @Override
+ public void onDeviceAdded(Preference preference) {
+ mPreferenceSize++;
+ if (mPreferenceSize <= MAX_DEVICE_NUM) {
+ mPreferenceGroup.addPreference(preference);
+ }
+ updatePreferenceVisiblity();
+ }
+
+ @Override
+ public void onDeviceRemoved(Preference preference) {
+ mPreferenceSize--;
+ mPreferenceGroup.removePreference(preference);
+ updatePreferenceVisiblity();
+ }
+
+ void updatePreferenceVisiblity() {
+ if ((mLocalAdapter != null) && (mLocalAdapter.getBluetoothState()
+ == BluetoothAdapter.STATE_ON)) {
+ mPreferenceGroup.setVisible(mPreferenceSize > 0);
+ } else {
+ mPreferenceGroup.setVisible(false);
+ }
+ }
+
+ @Override
+ public void onBluetoothStateChanged(int bluetoothState) {
+ updatePreferenceVisiblity();
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/GroupSavedDeviceController.java b/src/com/android/settings/connecteddevice/GroupSavedDeviceController.java
new file mode 100644
index 0000000000..5edde0819a
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/GroupSavedDeviceController.java
@@ -0,0 +1,164 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.android.settings.connecteddevice;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+import com.android.settings.bluetooth.BluetoothDevicePreference;
+import com.android.settings.bluetooth.BluetoothDeviceUpdater;
+import com.android.settings.bluetooth.GroupBluetoothSettingsPreference;
+import com.android.settings.bluetooth.GroupUtils;
+import com.android.settings.bluetooth.GroupSavedBluetoothDeviceUpdater;
+import com.android.settings.connecteddevice.dock.DockUpdater;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.DockUpdaterFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.GearPreference;
+import com.android.settings.widget.GearPreference.OnGearClickListener;
+import com.android.settings.widget.GroupPreferenceCategory;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+import com.android.settings.R;
+
+/**
+ * Controller to maintain the {@link PreferenceGroup} for all
+ * saved group devices. It uses {@link DevicePreferenceCallback}
+ * to add/remove {@link Preference}
+ */
+public class GroupSavedDeviceController extends BasePreferenceController
+ implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop,
+ DevicePreferenceCallback , OnGearClickListener {
+
+ private static final String KEY = "group_saved_device_list";
+ private static final String KEY_PCG_ONE = "pcg_one";
+ private static final String KEY_PCG_TWO = "pcg_two";
+ private static final String KEY_PCG_THREE = "pcg_three";
+ private static final String KEY_PCG_FOUR = "pcg_four";
+ private static final String KEY_PCG_FIVE = "pcg_five";
+ private static final String KEY_PCG_SIX = "pcg_six";
+ private static final String KEY_PCG_SEVEN = "pcg_seven";
+ private static final String KEY_PCG_EIGHT = "pcg_eight";
+ private static final String KEY_PCG_NINE = "pcg_nine";
+ private static final String KEY_PCG_REMAINING = "pcg_remaining";
+ private static final String TAG = "GroupSavedDeviceController";
+ private PreferenceGroup mPreferenceGroup;
+ private GroupSavedBluetoothDeviceUpdater mBluetoothDeviceUpdater;
+ private GroupBluetoothSettingsPreference mGroupPreference;
+ private GroupUtils mGroupUtils;
+ private ArrayList<GroupPreferenceCategory> mListCategories =
+ new ArrayList<GroupPreferenceCategory>();
+ GroupPreferenceCategory mPreferenceGroupRemaining;
+
+ public GroupSavedDeviceController(Context context) {
+ super(context, KEY);
+ DockUpdaterFeatureProvider dockUpdaterFeatureProvider =
+ FeatureFactory.getFactory(context).getDockUpdaterFeatureProvider();
+ }
+
+ @Override
+ public void onStart() {
+ mBluetoothDeviceUpdater.registerCallback();
+ }
+
+ @Override
+ public void onStop() {
+ mBluetoothDeviceUpdater.unregisterCallback();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ mPreferenceGroup = screen.findPreference(KEY);
+ mPreferenceGroup.setVisible(false);
+ mListCategories.add(screen.findPreference(KEY_PCG_ONE));
+ mListCategories.add(screen.findPreference(KEY_PCG_TWO));
+ mListCategories.add(screen.findPreference(KEY_PCG_THREE));
+ mListCategories.add(screen.findPreference(KEY_PCG_FOUR));
+ mListCategories.add(screen.findPreference(KEY_PCG_FIVE));
+ mListCategories.add(screen.findPreference(KEY_PCG_SIX));
+ mListCategories.add(screen.findPreference(KEY_PCG_SEVEN));
+ mListCategories.add(screen.findPreference(KEY_PCG_EIGHT));
+ mListCategories.add(screen.findPreference(KEY_PCG_NINE));
+ mPreferenceGroupRemaining = screen.findPreference(KEY_PCG_REMAINING);
+ mPreferenceGroupRemaining.setGroupId(-99);
+ mListCategories.add(mPreferenceGroupRemaining);
+
+ if (isAvailable()) {
+ final Context context = screen.getContext();
+ mGroupUtils = new GroupUtils(context);
+ mBluetoothDeviceUpdater.setPrefContext(context);
+ mBluetoothDeviceUpdater.forceUpdate();
+ }
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH))
+ ? AVAILABLE
+ : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY;
+ }
+
+ @Override
+ public void onDeviceAdded(Preference preference) {
+ mGroupUtils.addPreference(mListCategories, preference, this);
+ }
+
+ @Override
+ public void onDeviceRemoved(Preference preference) {
+ mGroupUtils.removePreference(mListCategories, preference);
+ }
+
+ public void init(DashboardFragment fragment) {
+ mBluetoothDeviceUpdater = new GroupSavedBluetoothDeviceUpdater(fragment.getContext(),
+ fragment, GroupSavedDeviceController.this);
+ }
+
+ @Override
+ public void onGearClick(GearPreference p) {
+ GroupBluetoothSettingsPreference pre = (GroupBluetoothSettingsPreference) p;
+ mBluetoothDeviceUpdater.launchgroupOptions(pre);
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java b/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java
index 4469d265ae..749e6de898 100644
--- a/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/PreviouslyConnectedDevicePreferenceController.java
@@ -28,7 +28,13 @@ import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
+import android.bluetooth.BluetoothAdapter;
+import com.android.settingslib.bluetooth.BluetoothCallback;
+import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settings.bluetooth.Utils;
import com.android.settings.R;
import com.android.settings.bluetooth.BluetoothDevicePreference;
import com.android.settings.bluetooth.BluetoothDeviceUpdater;
@@ -45,7 +51,7 @@ import java.util.ArrayList;
import java.util.List;
public class PreviouslyConnectedDevicePreferenceController extends BasePreferenceController
- implements LifecycleObserver, OnStart, OnStop, DevicePreferenceCallback {
+ implements LifecycleObserver, OnStart, OnStop, DevicePreferenceCallback, BluetoothCallback {
private static final String TAG = "PreviouslyDevicePreController";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -58,6 +64,8 @@ public class PreviouslyConnectedDevicePreferenceController extends BasePreferenc
private final List<Preference> mDockDevicesList = new ArrayList<>();
private PreferenceGroup mPreferenceGroup;
+ private LocalBluetoothAdapter mLocalAdapter;
+ private LocalBluetoothManager manager;
private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
private DockUpdater mSavedDockUpdater;
private BluetoothAdapter mBluetoothAdapter;
@@ -82,6 +90,10 @@ public class PreviouslyConnectedDevicePreferenceController extends BasePreferenc
context).getDockUpdaterFeatureProvider().getSavedDockUpdater(context, this);
mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
+ manager = Utils.getLocalBtManager(context);
+ if ( manager != null) {
+ mLocalAdapter = manager.getBluetoothAdapter();
+ }
}
@Override
@@ -113,6 +125,7 @@ public class PreviouslyConnectedDevicePreferenceController extends BasePreferenc
mSavedDockUpdater.registerCallback();
mContext.registerReceiver(mReceiver, mIntentFilter);
mBluetoothDeviceUpdater.refreshPreference();
+ manager.getEventManager().registerCallback(this);
}
@Override
@@ -120,6 +133,8 @@ public class PreviouslyConnectedDevicePreferenceController extends BasePreferenc
mBluetoothDeviceUpdater.unregisterCallback();
mSavedDockUpdater.unregisterCallback();
mContext.unregisterReceiver(mReceiver);
+ manager.getEventManager().unregisterCallback(this);
+
}
public void init(DashboardFragment fragment) {
@@ -202,6 +217,46 @@ public class PreviouslyConnectedDevicePreferenceController extends BasePreferenc
updatePreferenceVisibility();
}
+ @Override
+ public void onBluetoothStateChanged(int bluetoothState) {
+ updatePreferenceVisibility();
+ }
+
+ @Override
+ public void onScanningStateChanged(boolean started) {
+ // do nothing
+ }
+
+ @Override
+ public void onDeviceAdded(CachedBluetoothDevice cachedDevice) {
+ // do nothing
+ }
+
+ @Override
+ public void onDeviceDeleted(CachedBluetoothDevice cachedDevice) {
+ // do nothing
+ }
+
+ @Override
+ public void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState) {
+ // do nothing
+ }
+
+ @Override
+ public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
+ // do nothing
+ }
+
+ @Override
+ public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
+ // do nothing
+ }
+
+ @Override
+ public void onAudioModeChanged() {
+ // do nothing
+ }
+
@VisibleForTesting
void setBluetoothDeviceUpdater(BluetoothDeviceUpdater bluetoothDeviceUpdater) {
mBluetoothDeviceUpdater = bluetoothDeviceUpdater;
@@ -226,4 +281,5 @@ public class PreviouslyConnectedDevicePreferenceController extends BasePreferenc
mContext.getString(R.string.connected_device_see_all_summary));
}
}
+
}
diff --git a/src/com/android/settings/connecteddevice/SavedTwsDeviceGroupController.java b/src/com/android/settings/connecteddevice/SavedTwsDeviceGroupController.java
new file mode 100644
index 0000000000..1e1f0ac3ee
--- /dev/null
+++ b/src/com/android/settings/connecteddevice/SavedTwsDeviceGroupController.java
@@ -0,0 +1,157 @@
+/*
+ *Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted (subject to the limitations in the
+ * disclaimer below) provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+
+ * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+ * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+ * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.connecteddevice;
+
+import android.content.pm.PackageManager;
+import android.content.Context;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.bluetooth.BluetoothDeviceUpdater;
+import com.android.settings.bluetooth.SavedBluetoothTwsDeviceUpdater;
+import com.android.settings.connecteddevice.dock.DockUpdater;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.overlay.DockUpdaterFeatureProvider;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+/**
+ * Controller to maintain the {@link PreferenceGroup} for all
+ * saved TWS+ devices. It uses {@link DevicePreferenceCallback} to add/remove {@link Preference}
+ */
+public class SavedTwsDeviceGroupController extends BasePreferenceController
+ implements PreferenceControllerMixin, LifecycleObserver, OnStart, OnStop,
+ DevicePreferenceCallback {
+
+ private static final String KEY = "saved_tws_device_list";
+
+ PreferenceGroup mPreferenceGroup;
+ private BluetoothDeviceUpdater mBluetoothDeviceUpdater;
+ private DockUpdater mSavedDockUpdater;
+
+ public SavedTwsDeviceGroupController(Context context) {
+ super(context, KEY);
+
+ DockUpdaterFeatureProvider dockUpdaterFeatureProvider =
+ FeatureFactory.getFactory(context).getDockUpdaterFeatureProvider();
+ mSavedDockUpdater =
+ dockUpdaterFeatureProvider.getSavedDockUpdater(context, this);
+ }
+
+ @Override
+ public void onStart() {
+ mBluetoothDeviceUpdater.registerCallback();
+ mSavedDockUpdater.registerCallback();
+ }
+
+ @Override
+ public void onStop() {
+ mBluetoothDeviceUpdater.unregisterCallback();
+ mSavedDockUpdater.unregisterCallback();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ if (isAvailable()) {
+ mPreferenceGroup = (PreferenceGroup) screen.findPreference(KEY);
+ mPreferenceGroup.setVisible(false);
+ mBluetoothDeviceUpdater.setPrefContext(screen.getContext());
+ mBluetoothDeviceUpdater.forceUpdate();
+ mSavedDockUpdater.forceUpdate();
+ }
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)
+ ? AVAILABLE
+ : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY;
+ }
+
+ @Override
+ public void onDeviceAdded(Preference preference) {
+ if (mPreferenceGroup.getPreferenceCount() == 0) {
+ mPreferenceGroup.setVisible(true);
+ }
+ mPreferenceGroup.addPreference(preference);
+ }
+
+ @Override
+ public void onDeviceRemoved(Preference preference) {
+ mPreferenceGroup.removePreference(preference);
+ if (mPreferenceGroup.getPreferenceCount() == 0) {
+ mPreferenceGroup.setVisible(false);
+ }
+ }
+
+ public void init(DashboardFragment fragment) {
+ mBluetoothDeviceUpdater = new SavedBluetoothTwsDeviceUpdater(fragment.getContext(),
+ fragment, SavedTwsDeviceGroupController.this);
+ }
+
+ public void setBluetoothDeviceUpdater(BluetoothDeviceUpdater bluetoothDeviceUpdater) {
+ mBluetoothDeviceUpdater = bluetoothDeviceUpdater;
+ }
+
+ public void setSavedDockUpdater(DockUpdater savedDockUpdater) {
+ mSavedDockUpdater = savedDockUpdater;
+ }
+}
diff --git a/src/com/android/settings/connecteddevice/usb/UsbBackend.java b/src/com/android/settings/connecteddevice/usb/UsbBackend.java
index 244818fe16..15922005d4 100644
--- a/src/com/android/settings/connecteddevice/usb/UsbBackend.java
+++ b/src/com/android/settings/connecteddevice/usb/UsbBackend.java
@@ -41,7 +41,10 @@ import java.util.List;
*/
public class UsbBackend {
- static final int PD_ROLE_SWAP_TIMEOUT_MS = 3000;
+ // extend this value from 3s to 4s because of switching data role
+ // in USB driver side takes about 3s, plus the usb port change event
+ // dispatching time, 3s is not enough.
+ static final int PD_ROLE_SWAP_TIMEOUT_MS = 4000;
static final int NONPD_ROLE_SWAP_TIMEOUT_MS = 15000;
private final boolean mFileTransferRestricted;
diff --git a/src/com/android/settings/core/TogglePreferenceController.java b/src/com/android/settings/core/TogglePreferenceController.java
index 8b4d6d9c57..e7acc8c335 100644
--- a/src/com/android/settings/core/TogglePreferenceController.java
+++ b/src/com/android/settings/core/TogglePreferenceController.java
@@ -16,6 +16,7 @@ package com.android.settings.core;
import android.content.Context;
import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
import androidx.preference.TwoStatePreference;
import com.android.settings.overlay.FeatureFactory;
@@ -64,6 +65,15 @@ public abstract class TogglePreferenceController extends BasePreferenceControlle
}
@Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ Preference preference = screen.findPreference(getPreferenceKey());
+ if (preference != null) {
+ preference.setOnPreferenceChangeListener(this);
+ }
+ }
+
+ @Override
public final boolean onPreferenceChange(Preference preference, Object newValue) {
// TwoStatePreference is a regular preference and can be handled by DashboardFragment
if (preference instanceof PrimarySwitchPreference
@@ -92,4 +102,4 @@ public abstract class TogglePreferenceController extends BasePreferenceControlle
@Override
public abstract int getSliceHighlightMenuRes();
-} \ No newline at end of file
+}
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 804f856a13..4c9f37b424 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -67,12 +67,14 @@ import com.android.settings.biometrics.combination.CombinedBiometricProfileSetti
import com.android.settings.biometrics.combination.CombinedBiometricSettings;
import com.android.settings.biometrics.face.FaceSettings;
import com.android.settings.biometrics.fingerprint.FingerprintSettings;
+import com.android.settings.bluetooth.GroupBluetoothFragment;
import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
import com.android.settings.bluetooth.BluetoothPairingDetail;
import com.android.settings.bugreporthandler.BugReportHandlerPicker;
import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
import com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment;
+import com.android.settings.connecteddevice.GroupPreviouslyConnectedDeviceDashboardFragment;
import com.android.settings.connecteddevice.usb.UsbDetailsFragment;
import com.android.settings.datausage.DataSaverSummary;
import com.android.settings.datausage.DataUsageList;
@@ -308,9 +310,11 @@ public class SettingsGateway {
WebViewAppPicker.class.getName(),
LockscreenDashboardFragment.class.getName(),
BluetoothDeviceDetailsFragment.class.getName(),
+ GroupBluetoothFragment.class.getName(),
DataUsageList.class.getName(),
ToggleBackupSettingFragment.class.getName(),
PreviouslyConnectedDeviceDashboardFragment.class.getName(),
+ GroupPreviouslyConnectedDeviceDashboardFragment.class.getName(),
BatterySaverScheduleSettings.class.getName(),
MobileNetworkListFragment.class.getName(),
PowerMenuSettings.class.getName(),
diff --git a/src/com/android/settings/datausage/BillingCyclePreference.java b/src/com/android/settings/datausage/BillingCyclePreference.java
index 116ed89b3c..6fc403b981 100644
--- a/src/com/android/settings/datausage/BillingCyclePreference.java
+++ b/src/com/android/settings/datausage/BillingCyclePreference.java
@@ -72,6 +72,7 @@ public class BillingCyclePreference extends Preference
setSummary(null);
setIntent(getIntent());
+ updateEnabled();
}
private void updateEnabled() {
diff --git a/src/com/android/settings/datausage/CellDataPreference.java b/src/com/android/settings/datausage/CellDataPreference.java
index 0e47bc4f2c..852f5fc31a 100644
--- a/src/com/android/settings/datausage/CellDataPreference.java
+++ b/src/com/android/settings/datausage/CellDataPreference.java
@@ -65,7 +65,6 @@ public class CellDataPreference extends CustomDialogPreferenceCompat
final CellDataState state = (CellDataState) s;
super.onRestoreInstanceState(state.getSuperState());
mChecked = state.mChecked;
- mMultiSimDialog = state.mMultiSimDialog;
if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
mSubId = state.mSubId;
setKey(getKey() + mSubId);
@@ -77,7 +76,6 @@ public class CellDataPreference extends CustomDialogPreferenceCompat
protected Parcelable onSaveInstanceState() {
final CellDataState state = new CellDataState(super.onSaveInstanceState());
state.mChecked = mChecked;
- state.mMultiSimDialog = mMultiSimDialog;
state.mSubId = mSubId;
return state;
}
@@ -138,6 +136,7 @@ public class CellDataPreference extends CustomDialogPreferenceCompat
@Override
protected void performClick(View view) {
final Context context = getContext();
+ // TODO (b/123905421): Clean up dead code path
FeatureFactory.getFactory(context).getMetricsFeatureProvider()
.action(context, SettingsEnums.ACTION_CELL_DATA_TOGGLE, !mChecked);
final SubscriptionInfo currentSir = getActiveSubscriptionInfo(mSubId);
@@ -178,11 +177,7 @@ public class CellDataPreference extends CustomDialogPreferenceCompat
@Override
protected void onPrepareDialogBuilder(Builder builder,
DialogInterface.OnClickListener listener) {
- if (mMultiSimDialog) {
- showMultiSimDialog(builder, listener);
- } else {
- showDisableDialog(builder, listener);
- }
+ showDisableDialog(builder, listener);
}
private void showDisableDialog(Builder builder,
@@ -193,6 +188,7 @@ public class CellDataPreference extends CustomDialogPreferenceCompat
.setNegativeButton(android.R.string.cancel, null);
}
+ // TODO (b/123905421): Clean up dead code path
private void showMultiSimDialog(Builder builder,
DialogInterface.OnClickListener listener) {
final SubscriptionInfo currentSir = getActiveSubscriptionInfo(mSubId);
@@ -226,14 +222,8 @@ public class CellDataPreference extends CustomDialogPreferenceCompat
if (which != DialogInterface.BUTTON_POSITIVE) {
return;
}
- if (mMultiSimDialog) {
- getProxySubscriptionManager().get().setDefaultDataSubId(mSubId);
- setMobileDataEnabled(true);
- disableDataForOtherSubscriptions(mSubId);
- } else {
- // TODO: extend to modify policy enabled flag.
- setMobileDataEnabled(false);
- }
+ // TODO: extend to modify policy enabled flag.
+ setMobileDataEnabled(false);
}
@VisibleForTesting
@@ -259,7 +249,6 @@ public class CellDataPreference extends CustomDialogPreferenceCompat
public static class CellDataState extends BaseSavedState {
public int mSubId;
public boolean mChecked;
- public boolean mMultiSimDialog;
public CellDataState(Parcelable base) {
super(base);
@@ -268,7 +257,6 @@ public class CellDataPreference extends CustomDialogPreferenceCompat
public CellDataState(Parcel source) {
super(source);
mChecked = source.readByte() != 0;
- mMultiSimDialog = source.readByte() != 0;
mSubId = source.readInt();
}
@@ -276,7 +264,6 @@ public class CellDataPreference extends CustomDialogPreferenceCompat
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeByte((byte) (mChecked ? 1 : 0));
- dest.writeByte((byte) (mMultiSimDialog ? 1 : 0));
dest.writeInt(mSubId);
}
diff --git a/src/com/android/settings/datausage/DataUsageSummary.java b/src/com/android/settings/datausage/DataUsageSummary.java
index a4396a286c..112ea87b94 100644
--- a/src/com/android/settings/datausage/DataUsageSummary.java
+++ b/src/com/android/settings/datausage/DataUsageSummary.java
@@ -27,6 +27,7 @@ import android.text.SpannableString;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.text.style.RelativeSizeSpan;
+import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -96,7 +97,19 @@ public class DataUsageSummary extends DataUsageBaseFragment implements DataUsage
}
boolean hasWifiRadio = DataUsageUtils.hasWifiRadio(context);
if (hasMobileData) {
- addMobileSection(defaultSubId);
+ List<SubscriptionInfo> subscriptions =
+ services.mSubscriptionManager.getActiveSubscriptionInfoList();
+ if (subscriptions == null || subscriptions.size() == 0) {
+ addMobileSection(defaultSubId);
+ }
+ for (int i = 0; subscriptions != null && i < subscriptions.size(); i++) {
+ SubscriptionInfo subInfo = subscriptions.get(i);
+ if (subscriptions.size() > 1) {
+ addMobileSection(subInfo.getSubscriptionId(), subInfo);
+ } else {
+ addMobileSection(subInfo.getSubscriptionId());
+ }
+ }
if (hasActiveSubscription() && hasWifiRadio) {
// If the device has active SIM, the data usage section shows usage for mobile,
// and the WiFi section is added if there is a WiFi radio - legacy behavior.
diff --git a/src/com/android/settings/development/BluetoothSnoopLogPreferenceController.java b/src/com/android/settings/development/BluetoothSnoopLogPreferenceController.java
index d698436176..58550c96c9 100644
--- a/src/com/android/settings/development/BluetoothSnoopLogPreferenceController.java
+++ b/src/com/android/settings/development/BluetoothSnoopLogPreferenceController.java
@@ -44,6 +44,11 @@ public class BluetoothSnoopLogPreferenceController extends DeveloperOptionsPrefe
@VisibleForTesting
static final int BTSNOOP_LOG_MODE_FULL_INDEX = 2;
@VisibleForTesting
+ static final int BTSNOOP_LOG_MODE_SNOOPHEADERSFILTERED_INDEX = 3;
+ @VisibleForTesting
+ static final int BTSNOOP_LOG_MODE_MEDIAPKTSFILTERED_INDEX = 4;
+ @VisibleForTesting
+
static final String BLUETOOTH_BTSNOOP_LOG_MODE_PROPERTY = "persist.bluetooth.btsnooplogmode";
private final String[] mListValues;
@@ -97,8 +102,13 @@ public class BluetoothSnoopLogPreferenceController extends DeveloperOptionsPrefe
break;
}
}
- listPreference.setValue(mListValues[index]);
- listPreference.setSummary(mListEntries[index]);
+ if( index < mListValues.length && index < mListEntries.length ) {
+ listPreference.setValue(mListValues[index]);
+ listPreference.setSummary(mListEntries[index]);
+ } else {
+ Log.e(TAG, "missing some entries in xml file"
+ + "\t some options in developer options will not be shown until added in xml file");
+ }
}
@Override
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index fbab1fd124..ea6d9cf5e7 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -261,6 +261,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
@Override
public void onDestroyView() {
super.onDestroyView();
+ Context context = getContext();
+ SmartDdsSwitchPreferenceController.getInstance(context).cleanUp();
unregisterReceivers();
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -468,6 +470,8 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
Activity activity, Lifecycle lifecycle, DevelopmentSettingsDashboardFragment fragment,
BluetoothA2dpConfigStore bluetoothA2dpConfigStore) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ controllers.add(new Prefer5GNetworkSummaryController(context, lifecycle));
+ controllers.add(new PreferVonrController(context, lifecycle));
controllers.add(new MemoryUsagePreferenceController(context));
controllers.add(new BugReportPreferenceController(context));
controllers.add(new BugReportHandlerPreferenceController(context));
@@ -503,10 +507,12 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new LogPersistPreferenceController(context, fragment, lifecycle));
controllers.add(new CameraLaserSensorPreferenceController(context));
controllers.add(new WifiDisplayCertificationPreferenceController(context));
+ controllers.add(new WifiCoverageExtendPreferenceController(context));
controllers.add(new WifiVerboseLoggingPreferenceController(context));
controllers.add(new WifiScanThrottlingPreferenceController(context));
controllers.add(new WifiEnhancedMacRandomizationPreferenceController(context));
controllers.add(new MobileDataAlwaysOnPreferenceController(context));
+ controllers.add(SmartDdsSwitchPreferenceController.getInstance(context));
controllers.add(new TetheringHardwareAccelPreferenceController(context));
controllers.add(new BluetoothDeviceNoNamePreferenceController(context));
controllers.add(new BluetoothAbsoluteVolumePreferenceController(context));
@@ -597,6 +603,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
@Override
public void onBluetoothHDAudioEnabled(boolean enabled) {
+ Log.d(TAG, "onBluetoothHDAudioEnabled: " + enabled);
for (AbstractPreferenceController controller : mPreferenceControllers) {
if (controller instanceof AbstractBluetoothDialogPreferenceController) {
((AbstractBluetoothDialogPreferenceController) controller).onHDAudioEnabled(
diff --git a/src/com/android/settings/development/Prefer5GNetworkListController.java b/src/com/android/settings/development/Prefer5GNetworkListController.java
new file mode 100644
index 0000000000..ce7face9be
--- /dev/null
+++ b/src/com/android/settings/development/Prefer5GNetworkListController.java
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved
+ * Not a contribution
+ *
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
+import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.preference.PreferenceManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.ListPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.settings.R;
+import com.android.settings.network.SubscriptionUtil;
+import com.android.settings.network.SubscriptionsChangeListener;
+import com.android.settings.network.telephony.MobileNetworkUtils;
+import com.android.settingslib.core.AbstractPreferenceController;
+
+import com.qti.extphone.Client;
+import com.qti.extphone.ExtTelephonyManager;
+import com.qti.extphone.ExtPhoneCallbackBase;
+import com.qti.extphone.NrConfig;
+import com.qti.extphone.Status;
+import com.qti.extphone.ServiceCallback;
+import com.qti.extphone.Token;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This populates the entries on a page which lists all available mobile subscriptions. Each entry
+ * has the name of the subscription with some subtext giving additional detail, and clicking on the
+ * entry brings you to a details page for that network.
+ */
+public class Prefer5GNetworkListController extends AbstractPreferenceController implements
+ LifecycleObserver, ListPreference.OnPreferenceChangeListener,
+ SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+ private static final String TAG = "Prefer5gNetworkListCtlr";
+
+ @VisibleForTesting
+ static final String KEY_ADD_MORE = "prefer_5g_add_more";
+ private static final int NR_MODE_NSA_SA = 0;
+ private static final int NR_MODE_NSA = 1;
+ private static final int NR_MODE_SA = 2;
+ private static final int EVENT_SET_NR_CONFIG_STATUS = 101;
+ private static final int EVENT_GET_NR_CONFIG_STATUS = 102;
+
+ private Client mClient;
+ private Context mContext;
+ private String mPackageName;
+ private SharedPreferences mSharedPreferences;
+ private SubscriptionManager mSubscriptionManager;
+ private SubscriptionsChangeListener mChangeListener;
+ private PreferenceScreen mPreferenceScreen;
+ private TelephonyManager mTelephonyManager;
+ private Map<Integer, ListPreference> mPreferences;
+ private List<ListPreference> mPreferenceList;
+
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private int mPhoneId = SubscriptionManager.INVALID_PHONE_INDEX;
+ private int userPrefNrConfig;
+ private ExtTelephonyManager mExtTelephonyManager;
+ private boolean mServiceConnected;
+ private boolean mRetry;
+
+ private ExtPhoneCallbackBase mCallback = new ExtPhoneCallbackBase() {
+ @Override
+ public void onSetNrConfig(int slotId, Token token, Status status) throws
+ RemoteException {
+ Log.d(TAG, "onSetNrConfig: slotId = " + slotId + " token = " + token + " status = " +
+ status);
+ if (status.get() == Status.SUCCESS) {
+ updateSharedPreference(slotId, userPrefNrConfig);
+ }
+ mMainThreadHandler.sendMessage(mMainThreadHandler
+ .obtainMessage(EVENT_SET_NR_CONFIG_STATUS, slotId, -1));
+ }
+
+ @Override
+ public void onNrConfigStatus(int slotId, Token token, Status status, NrConfig nrConfig)
+ throws RemoteException {
+ Log.d(TAG, "onNrConfigStatus: slotId = " + slotId + " token = " + token + " status = " +
+ status + " nrConfig = " + nrConfig);
+ if (status.get() == Status.SUCCESS) {
+ updateSharedPreference(slotId, nrConfig.get());
+ mMainThreadHandler.sendMessage(mMainThreadHandler
+ .obtainMessage(EVENT_GET_NR_CONFIG_STATUS, slotId, -1));
+ }
+ }
+ };
+
+ private Handler mMainThreadHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ Log.d(TAG, "handleMessage msg.what = " + msg.what);
+ switch (msg.what) {
+ case EVENT_SET_NR_CONFIG_STATUS:
+ case EVENT_GET_NR_CONFIG_STATUS: {
+ int slotId = msg.arg1;
+ if (mPreferenceScreen != null) {
+ updatePreferenceForSlot(slotId);
+ }
+ break;
+ }
+ }
+ }
+ };
+
+ private void updateSharedPreference(int slotId, int nrConfig) {
+ if (mSharedPreferences != null) {
+ mSharedPreferences.edit().putInt("nr_mode_" + slotId, nrConfig).apply();
+ }
+ }
+
+
+ public Prefer5GNetworkListController(Context context, Lifecycle lifecycle) {
+ super(context);
+ Log.i(TAG, "constructor");
+ mContext = context;
+ mPackageName = mContext.getPackageName();
+ mSharedPreferences = mContext.getSharedPreferences(mContext.getPackageName(),
+ mContext.MODE_PRIVATE);
+ mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
+ mChangeListener = new SubscriptionsChangeListener(context, this);
+ mPreferences = new ArrayMap<>();
+ if (mExtTelephonyManager == null) {
+ mExtTelephonyManager = ExtTelephonyManager.getInstance(
+ mContext.getApplicationContext());
+ }
+ Log.d(TAG, "Connect to ExtTelephony bound service...");
+ mExtTelephonyManager.connectService(mServiceCallback);
+
+ lifecycle.addObserver(this);
+ }
+
+ private ServiceCallback mServiceCallback = new ServiceCallback() {
+ @Override
+ public void onConnected() {
+ Log.d(TAG, "ExtTelephony Service connected");
+ mServiceConnected = true;
+ mClient = mExtTelephonyManager.registerCallback(mPackageName, mCallback);
+ Log.d(TAG, "Client = " + mClient);
+ if (mRetry) {
+ for (int slotId = 0; slotId < mTelephonyManager.getPhoneCount();
+ slotId++) {
+ mRetry = false;
+ Token token = mExtTelephonyManager.queryNrConfig(slotId, mClient);
+ Log.d(TAG, "queryNrConfig: " + token);
+ }
+ }
+ }
+
+ @Override
+ public void onDisconnected() {
+ Log.d(TAG, "ExtTelephony Service disconnected...");
+ if (mServiceConnected) {
+ mServiceConnected = false;
+ mClient = null;
+ }
+ }
+ };
+
+ @OnLifecycleEvent(ON_RESUME)
+ public void onResume() {
+ Log.i(TAG, "onResume");
+ mChangeListener.start();
+ update();
+ }
+
+ @OnLifecycleEvent(ON_PAUSE)
+ public void onPause() {
+ mChangeListener.stop();
+ }
+
+ @OnLifecycleEvent(ON_DESTROY)
+ protected void onDestroy() {
+ Log.d(TAG, "onDestroy");
+ mExtTelephonyManager.unRegisterCallback(mCallback);
+ mExtTelephonyManager.disconnectService();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ Log.i(TAG, "displayPreference");
+ mPreferenceScreen = screen;
+ mPreferenceScreen.findPreference(KEY_ADD_MORE).setVisible(
+ MobileNetworkUtils.showEuiccSettings(mContext));
+ }
+
+ private void update() {
+ if (mPreferenceScreen == null) {
+ return;
+ }
+
+ // Since we may already have created some preferences previously, we first grab the list of
+ // those, then go through the current available subscriptions making sure they are all
+ // present in the screen, and finally remove any now-outdated ones.
+ final Map<Integer, ListPreference> existingPreferences = mPreferences;
+ mPreferences = new ArrayMap<>();
+ mPreferenceList = new ArrayList<>();
+
+ for (int slotId = 0; slotId < mTelephonyManager.getPhoneCount();
+ slotId++) {
+ SubscriptionInfo info = mSubscriptionManager.
+ getActiveSubscriptionInfoForSimSlotIndex(slotId);
+ if (info != null) {
+ final int subId = info.getSubscriptionId();
+ ListPreference pref = existingPreferences.remove(subId);
+ if (pref == null) {
+ pref = new ListPreference(mPreferenceScreen.getContext());
+ mPreferenceScreen.addPreference(pref);
+ }
+ pref.setTitle(info.getDisplayName());
+ pref.setOrder(slotId);
+ pref.setDialogTitle("Select NR Mode For Slot " + slotId);
+
+ pref.setOnPreferenceChangeListener(this);
+ pref.setEntries(R.array.preferred_5g_network_mode_choices);
+ pref.setEntryValues(R.array.preferred_5g_network_mode_values);
+ if (mServiceConnected && mClient != null) {
+ mRetry = false;
+ Token token = mExtTelephonyManager.queryNrConfig(slotId, mClient);
+ Log.d(TAG, "queryNrConfig: " + token);
+ } else {
+ mRetry = true;
+ }
+
+ mPreferences.put(subId, pref);
+ mPreferenceList.add(pref);
+ } else {
+ Log.d(TAG, "sub info is null, add null preference for slot: " + slotId);
+ mPreferenceList.add(slotId, null);
+ }
+ }
+ for (Preference pref : existingPreferences.values()) {
+ mPreferenceScreen.removePreference(pref);
+ }
+ }
+
+ private void updatePreferenceForSlot(int slotId) {
+ int nrConfig = mSharedPreferences.getInt("nr_mode_" + slotId,
+ NrConfig.NR_CONFIG_COMBINED_SA_NSA);
+ String text = mContext.getString(getSummaryResId(nrConfig));
+ Log.d(TAG, "updatePreferenceForSlot for " + slotId + " ,nr mode is " + nrConfig +
+ " , set summary to " + text);
+ ListPreference pref = mPreferenceList.get(slotId);
+ if (pref != null) {
+ pref.setSummary(text);
+ pref.setValue(Integer.toString(nrConfig));
+ }
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object object) {
+ final int newNrMode = Integer.parseInt((String) object);
+ final int slotId = mPreferenceList.indexOf(preference);
+ Log.i(TAG, "onPreferenceChange for slot: " + slotId + ", setNrConfig: " + newNrMode);
+ userPrefNrConfig = newNrMode;
+ if (mServiceConnected && mClient != null) {
+ Token token = mExtTelephonyManager.setNrConfig(
+ slotId, new NrConfig(newNrMode), mClient);
+ Log.d(TAG, "setNrConfig: " + token);
+ }
+ final ListPreference listPreference = (ListPreference) preference;
+ String summary = mContext.getString(getSummaryResId(newNrMode));
+ listPreference.setSummary(summary);
+ return true;
+ }
+
+ private int getSummaryResId(int nrMode) {
+ if (nrMode == NrConfig.NR_CONFIG_COMBINED_SA_NSA) {
+ return R.string.nr_nsa_sa;
+ } else if (nrMode == NrConfig.NR_CONFIG_NSA) {
+ return R.string.nr_nsa;
+ } else if (nrMode == NrConfig.NR_CONFIG_SA) {
+ return R.string.nr_sa;
+ } else {
+ return R.string.nr_nsa_sa;
+ }
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return null;
+ }
+
+ @Override
+ public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+ }
+
+ @Override
+ public void onSubscriptionsChanged() {
+ boolean isSubChanged = false;
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
+ mContext);
+ for (SubscriptionInfo info : subs) {
+ if (info == null) return;
+
+ final int subId = info.getSubscriptionId();
+ if (mPreferences.get(subId) == null) {
+ isSubChanged = true;
+ }
+ }
+
+ if (isSubChanged) {
+ Log.d(TAG, "sub changed, will update preference");
+ update();
+ }
+ }
+}
diff --git a/src/com/android/settings/development/Prefer5GNetworkListFragment.java b/src/com/android/settings/development/Prefer5GNetworkListFragment.java
new file mode 100644
index 0000000000..836c159e0c
--- /dev/null
+++ b/src/com/android/settings/development/Prefer5GNetworkListFragment.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved
+ * Not a contribution
+ *
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.os.UserManager;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.search.SearchIndexable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
+public class Prefer5GNetworkListFragment extends DashboardFragment {
+ private static final String LOG_TAG = "Prefer5GNetworkListFragment";
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.developer_mobile_network_list;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return LOG_TAG;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.MOBILE_NETWORK_LIST;
+ }
+
+ @Override
+ protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
+ final List<AbstractPreferenceController> controllers = new ArrayList<>();
+ controllers.add(new Prefer5GNetworkListController(getContext(), getLifecycle()));
+ return controllers;
+ }
+
+ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider(R.xml.developer_mobile_network_list) {
+
+ @Override
+ protected boolean isPageSearchEnabled(Context context) {
+ return context.getSystemService(UserManager.class).isAdminUser();
+ }
+ };
+}
diff --git a/src/com/android/settings/development/Prefer5GNetworkSummaryController.java b/src/com/android/settings/development/Prefer5GNetworkSummaryController.java
new file mode 100644
index 0000000000..b2cec8722c
--- /dev/null
+++ b/src/com/android/settings/development/Prefer5GNetworkSummaryController.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved
+ * Not a contribution
+ *
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserManager;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.euicc.EuiccManager;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.network.SubscriptionsChangeListener;
+import com.android.settings.network.SubscriptionUtil;
+import com.android.settings.network.telephony.MobileNetworkUtils;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.widget.AddPreference;
+import com.android.settingslib.Utils;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+import java.util.List;
+
+public class Prefer5GNetworkSummaryController extends AbstractPreferenceController implements
+ SubscriptionsChangeListener.SubscriptionsChangeListenerClient, LifecycleObserver,
+ PreferenceControllerMixin {
+ private static final String TAG = "Prefer5GNetSummaryCtlr";
+
+ private static final String KEY = "prefer_5G_nr_mode";
+
+ private final MetricsFeatureProvider mMetricsFeatureProvider;
+
+ private SubscriptionManager mSubscriptionManager;
+ private UserManager mUserManager;
+ private SubscriptionsChangeListener mChangeListener;
+ private AddPreference mPreference;
+
+ public Prefer5GNetworkSummaryController(Context context, Lifecycle lifecycle) {
+ super(context);
+ mMetricsFeatureProvider = FeatureFactory.getFactory(mContext).getMetricsFeatureProvider();
+ mSubscriptionManager = context.getSystemService(SubscriptionManager.class);
+ mUserManager = context.getSystemService(UserManager.class);
+ if (lifecycle != null) {
+ mChangeListener = new SubscriptionsChangeListener(context, this);
+ lifecycle.addObserver(this);
+ }
+ }
+
+ @OnLifecycleEvent(ON_RESUME)
+ public void onResume() {
+ mChangeListener.start();
+ update();
+ }
+
+ @OnLifecycleEvent(ON_PAUSE)
+ public void onPause() {
+ mChangeListener.stop();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
+ mContext);
+ if (subs.isEmpty()) {
+ if (MobileNetworkUtils.showEuiccSettings(mContext)) {
+ return mContext.getResources().getString(
+ R.string.mobile_network_summary_add_a_network);
+ }
+ return null;
+ } else {
+ final int count = subs.size();
+ return mContext.getResources().getQuantityString(R.plurals.mobile_network_summary_count,
+ count, count);
+ }
+ }
+
+ private void startAddSimFlow() {
+ final Intent intent = new Intent(EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTION);
+ intent.putExtra(EuiccManager.EXTRA_FORCE_PROVISION, true);
+ mContext.startActivity(intent);
+ }
+
+ private void update() {
+ if (mPreference == null || mPreference.isDisabledByAdmin()) {
+ return;
+ }
+ refreshSummary(mPreference);
+ mPreference.setOnPreferenceClickListener(null);
+ mPreference.setOnAddClickListener(null);
+ mPreference.setFragment(null);
+ mPreference.setEnabled(!mChangeListener.isAirplaneModeOn());
+
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
+ mContext);
+
+ if (subs.isEmpty()) {
+ if (MobileNetworkUtils.showEuiccSettings(mContext)) {
+ mPreference.setOnPreferenceClickListener((Preference pref) -> {
+ mMetricsFeatureProvider.logClickedPreference(pref,
+ pref.getExtras().getInt(DashboardFragment.CATEGORY));
+ startAddSimFlow();
+ return true;
+ });
+ } else {
+ mPreference.setEnabled(false);
+ }
+ } else {
+ // We have one or more existing subscriptions, so we want the plus button if eSIM is
+ // supported.
+ if (MobileNetworkUtils.showEuiccSettings(mContext)) {
+ mPreference.setAddWidgetEnabled(!mChangeListener.isAirplaneModeOn());
+ mPreference.setOnAddClickListener(p -> {
+ mMetricsFeatureProvider.logClickedPreference(p,
+ p.getExtras().getInt(DashboardFragment.CATEGORY));
+ startAddSimFlow();
+ });
+ }
+
+ mPreference.setFragment(Prefer5GNetworkListFragment.class.getCanonicalName());
+ }
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return !Utils.isWifiOnly(mContext) && mUserManager.isAdminUser();
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY;
+ }
+
+ @Override
+ public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+ update();
+ }
+
+ @Override
+ public void onSubscriptionsChanged() {
+ refreshSummary(mPreference);
+ update();
+ }
+}
diff --git a/src/com/android/settings/development/PreferVonrController.java b/src/com/android/settings/development/PreferVonrController.java
new file mode 100644
index 0000000000..6eab15e5b5
--- /dev/null
+++ b/src/com/android/settings/development/PreferVonrController.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved
+ * Not a contribution
+
+ * Copyright (C) 2019 The Android Open Source Project
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+
+import android.content.Context;
+import android.os.UserManager;
+import android.telephony.SubscriptionInfo;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+import com.android.settings.R;
+import com.android.settings.network.SubscriptionsChangeListener;
+import com.android.settings.network.SubscriptionUtil;
+import com.android.settingslib.Utils;
+
+import java.util.List;
+
+public class PreferVonrController extends DeveloperOptionsPreferenceController implements
+ SubscriptionsChangeListener.SubscriptionsChangeListenerClient, LifecycleObserver{
+ private static final String TAG = "PreferVonrCtlr";
+
+ private static final String KEY = "prefer_vonr_mode";
+
+
+ private UserManager mUserManager;
+ private SubscriptionsChangeListener mChangeListener;
+ private Preference mPreference;
+
+ public PreferVonrController(Context context, Lifecycle lifecycle) {
+ super(context);
+ mUserManager = context.getSystemService(UserManager.class);
+ mChangeListener = new SubscriptionsChangeListener(context, this);
+ if (lifecycle != null) {
+ lifecycle.addObserver(this);
+ }
+ }
+
+ @OnLifecycleEvent(ON_RESUME)
+ public void onResume() {
+ mChangeListener.start();
+ update();
+ }
+
+ @OnLifecycleEvent(ON_PAUSE)
+ public void onPause() {
+ mChangeListener.stop();
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ private void update() {
+ if (mPreference == null) {
+ return;
+ }
+ mPreference.setEnabled(!mChangeListener.isAirplaneModeOn());
+
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
+ mContext);
+
+ if (subs.isEmpty()) {
+ mPreference.setEnabled(false);
+ }
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return !Utils.isWifiOnly(mContext) && mUserManager.isAdminUser();
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY;
+ }
+
+ @Override
+ public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+ update();
+ }
+
+ @Override
+ public void onSubscriptionsChanged() {
+ update();
+ }
+}
diff --git a/src/com/android/settings/development/PreferVonrSettings.java b/src/com/android/settings/development/PreferVonrSettings.java
new file mode 100644
index 0000000000..34e6cbdb4d
--- /dev/null
+++ b/src/com/android/settings/development/PreferVonrSettings.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved
+ * Not a contribution
+
+ * Copyright (C) 2019 The Android Open Source Project
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.development;
+
+import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.telephony.ims.feature.MmTelFeature;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.os.Bundle;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import com.android.ims.ImsException;
+import com.android.ims.ImsManager;
+import com.android.settings.R;
+import com.android.settings.network.ims.VolteQueryImsState;
+import com.android.settings.network.SubscriptionUtil;
+import com.android.settings.network.SubscriptionsChangeListener;
+import com.android.settingslib.RestrictedSwitchPreference;
+import com.android.settings.SettingsPreferenceFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class PreferVonrSettings extends SettingsPreferenceFragment implements
+ SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
+ private static final String TAG = "PreferVonrSettings";
+ private static final int VONR_MODE_INVALID = -1;
+ private static final int VONR_MODE_OFF = 0;
+ private static final int VONR_MODE_ON = 1;
+ private static final String VONR_MODE_KEY = "vonr_mode_";
+ private SubscriptionManager mSubscriptionManager;
+ private SubscriptionsChangeListener mChangeListener;
+ private TelephonyManager mTelephonyManager;
+ private Map<Integer, RestrictedSwitchPreference> mPreferences;
+ private Context mContext;
+ private PreferenceScreen mPreferenceScreen;
+ private SharedPreferences mSharedPreferences;
+ private final List<RestrictedSwitchPreference> mPreferenceList = new ArrayList<>();
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Log.d(TAG, "onCreate");
+ if(getPreferenceScreen() == null) {
+ setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext()));
+ }
+ mPreferenceScreen = getPreferenceScreen();
+ addPreferencesFromResource(R.xml.prefer_vonr_list);
+ mContext = getPrefContext();
+ mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+ mChangeListener = new SubscriptionsChangeListener(mContext, this);
+ mPreferences = new ArrayMap<>();
+ mSharedPreferences = mContext.getSharedPreferences(mContext.getPackageName(),
+ mContext.MODE_PRIVATE);
+ }
+
+ @OnLifecycleEvent(ON_RESUME)
+ public void onResume() {
+ Log.d(TAG, "onResume");
+ super.onResume();
+ mChangeListener.start();
+ update();
+ }
+
+ @OnLifecycleEvent(ON_PAUSE)
+ public void onPause() {
+ super.onPause();
+ mChangeListener.stop();
+ }
+
+ private void update() {
+ Log.d(TAG, "update");
+ // Since we may already have created some preferences previously, we first grab the list of
+ // those, then go through the current available subscriptions making sure they are all
+ // present in the screen, and finally remove any now-outdated ones.
+ final Map<Integer, RestrictedSwitchPreference> existingPreferences = mPreferences;
+ mPreferences = new ArrayMap<>();
+
+ for (int slotId = 0; slotId < mTelephonyManager.getActiveModemCount();
+ slotId++) {
+ SubscriptionInfo info = mSubscriptionManager.
+ getActiveSubscriptionInfoForSimSlotIndex(slotId);
+ if (info != null) {
+ final int subId = info.getSubscriptionId();
+ RestrictedSwitchPreference pref = existingPreferences.remove(subId);
+ if (pref == null) {
+ pref = new RestrictedSwitchPreference(mContext);
+ mPreferenceScreen.addPreference(pref);
+ }
+ pref.setTitle(info.getDisplayName());
+ pref.setOrder(slotId);
+
+ mPreferences.put(subId, pref);
+ mPreferenceList.add(pref);
+ pref.setChecked(isVoNrSwitchChecked(slotId));
+ pref.setEnabled(isVoNrSwitchEnabled(subId, slotId));
+ maybeChangeNrCapability(slotId);
+ Log.d(TAG, "add preference for slot: " + slotId + " subId: " + subId);
+ } else {
+ Log.d(TAG, "sub info is null, add null preference for slot: " + slotId);
+ mPreferenceList.add(slotId, null);
+ }
+ }
+ for (Preference pref : existingPreferences.values()) {
+ mPreferenceScreen.removePreference(pref);
+ }
+ }
+
+ /**
+ * @return {@code true} if VoIMS opt-in has been enabled
+ * or VoLTE can be perform on this subscription,
+ * or VoNR is not supported by platform,
+ * {@code false} otherwise.
+ */
+ private boolean isVoNrSwitchEnabled(int subId, int slotId) {
+ ImsManager imsMgr = ImsManager.getInstance(mContext, slotId);
+ boolean isVoNrEnabledByCarrier = imsMgr.isImsOverNrEnabledByPlatform();
+ VolteQueryImsState queryImsState = new VolteQueryImsState(mContext, subId);
+ return (queryImsState.isVoImsOptInEnabled() || queryImsState.isReadyToVoLte())
+ && !isVoNrEnabledByCarrier;
+ }
+
+ /**
+ * @return {@code false} if VoLTE is off.
+ * @return {@code true} if VoLTE is on and supporting SA in carrier config.
+ * @return what user choose in this UI if VoLTE is on, but not supporting
+ * SA in carrier config
+ */
+ private boolean isVoNrSwitchChecked(int slotId) {
+ ImsManager imsMgr = ImsManager.getInstance(mContext, slotId);
+ boolean isVolteEnabled = imsMgr.isEnhanced4gLteModeSettingEnabledByUser();
+ if (!isVolteEnabled) {
+ return false;
+ }
+ boolean isVoNrEnabledByCarrier = imsMgr.isImsOverNrEnabledByPlatform();
+ int vonrMode = mSharedPreferences.getInt(VONR_MODE_KEY + slotId, VONR_MODE_INVALID);
+ boolean isVoNrEnabledByUser = vonrMode == VONR_MODE_ON;
+ Log.d(TAG, "enhanced 4g enabled: " + isVolteEnabled + ", vonr enabled by carrier: "
+ + isVoNrEnabledByCarrier + ", vonr enabled by user: " + isVoNrEnabledByUser
+ + " for slot: " + slotId);
+ return isVoNrEnabledByCarrier ? isVolteEnabled : isVoNrEnabledByUser;
+ }
+
+ /**
+ * This function is to make sure UI align with real capabilities.
+ * isVolteEnabled: the user option of "Enhanced 4g", true if enabled.
+ * isVoNrEnabledByCarrier: defined by carrier_nr_availabilities_int_array, true if
+ * SA is supported.
+ * isVoNrEnabledByUser: the user option of this UI, true if enabled.
+ * For china operator's sub, need this UI to enable/disable VoNR.
+ * For other subs, VoNR capability is been combined with VoLTE through "Enhanced 4g"
+ * option. We will not change NR capability here for other subs.
+ */
+ private void maybeChangeNrCapability(int slotId) {
+ ImsManager imsMgr = ImsManager.getInstance(mContext, slotId);
+ boolean isVolteEnabled = imsMgr.isEnhanced4gLteModeSettingEnabledByUser();
+ boolean isVoNrEnabledByCarrier = imsMgr.isImsOverNrEnabledByPlatform();
+ int vonrMode = mSharedPreferences.getInt(VONR_MODE_KEY + slotId, VONR_MODE_INVALID);
+ boolean isVoNrEnabledByUser = vonrMode == VONR_MODE_ON;
+ // If VoLTE is disabled, need to make sure VoNR is also disabled.
+ if (!isVolteEnabled && isVoNrEnabledByUser && !isVoNrEnabledByCarrier) {
+ changeNrCapability(imsMgr, false);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(Preference preference) {
+ final int slotId = mPreferenceList.indexOf(preference);
+ RestrictedSwitchPreference pref = (RestrictedSwitchPreference)preference;
+ Log.d(TAG, "onPreferenceTreeClick, preference isChecked: " + pref.isChecked()
+ + " for slot: " + slotId);
+
+ ImsManager imsMgr = ImsManager.getInstance(mContext, slotId);
+ boolean isImsEnabled = imsMgr.isEnhanced4gLteModeSettingEnabledByUser();
+ if (!isImsEnabled) {
+ Log.d(TAG, "onPreferenceTreeClick, ims is disabled, ignore the request");
+ return false;
+ }
+ changeNrCapability(imsMgr, pref.isChecked());
+ savePreferenceForSlot(slotId, pref.isChecked());
+ return super.onPreferenceTreeClick(preference);
+ }
+
+ private void changeNrCapability(ImsManager imsMgr, boolean enabled) {
+ try {
+ imsMgr.changeMmTelCapability(enabled,
+ MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE,
+ ImsRegistrationImplBase.REGISTRATION_TECH_NR);
+ } catch (ImsException e) {
+ Log.e(TAG, "Failed to change vonr mode to " + enabled + " since " + e);
+ }
+ }
+
+ private void savePreferenceForSlot(int slotId, boolean isChecked) {
+ if (mSharedPreferences != null) {
+ int vonr_mode = isChecked? VONR_MODE_ON: VONR_MODE_OFF;
+ mSharedPreferences.edit().putInt("vonr_mode_" + slotId, vonr_mode).apply();
+ }
+ }
+
+ @Override
+ public void onSubscriptionsChanged() {
+ final List<SubscriptionInfo> subs = SubscriptionUtil.getAvailableSubscriptions(
+ mContext);
+ for (SubscriptionInfo info : subs) {
+ if (info == null) return;
+
+ final int subId = info.getSubscriptionId();
+ if (mPreferences.get(subId) == null) {
+ Log.d(TAG, "sub changed, will update preference");
+ update();
+ break;
+ }
+ }
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.DEVELOPMENT;
+ }
+
+ @Override
+ public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+ }
+}
diff --git a/src/com/android/settings/development/SmartDdsSwitchPreferenceController.java b/src/com/android/settings/development/SmartDdsSwitchPreferenceController.java
new file mode 100644
index 0000000000..0a3a167dd0
--- /dev/null
+++ b/src/com/android/settings/development/SmartDdsSwitchPreferenceController.java
@@ -0,0 +1,242 @@
+/*
+Copyright (c) 2021 The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.android.settings.development;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import androidx.preference.Preference;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+import com.android.settings.R;
+
+import com.qti.extphone.Client;
+import com.qti.extphone.ExtPhoneCallbackBase;
+import com.qti.extphone.ExtTelephonyManager;
+import com.qti.extphone.ServiceCallback;
+import com.qti.extphone.Token;
+
+public class SmartDdsSwitchPreferenceController extends DeveloperOptionsPreferenceController
+ implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+ private final String TAG = "SmartDdsSwitchPreferenceController";
+
+ private final int EVENT_SET_DEFAULT_TOGGLE_STATE_RESPONSE = 1;
+
+ private final int SETTING_VALUE_ON = 1;
+ private final int SETTING_VALUE_OFF = 0;
+
+ private static SmartDdsSwitchPreferenceController mInstance;
+ private Client mClient;
+ private Context mContext;
+ private String mPackageName;
+ private final TelephonyManager mTelephonyManager;
+ private ExtTelephonyManager mExtTelephonyManager;
+ private boolean mFeatureAvailable = false;
+ private boolean mServiceConnected = false;
+ private boolean mSwitchEnabled = false;
+ private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ updateState(mPreference);
+ }
+ };
+
+ private SmartDdsSwitchPreferenceController(Context context) {
+ super(context);
+ Log.d(TAG, "Constructor");
+ mContext = context.getApplicationContext();
+ mPackageName = mContext.getPackageName();
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+ mExtTelephonyManager = ExtTelephonyManager.getInstance(mContext);
+ mExtTelephonyManager.connectService(mExtTelManagerServiceCallback);
+ IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
+ mContext.registerReceiver(mBroadcastReceiver, filter);
+ }
+
+ public static SmartDdsSwitchPreferenceController getInstance(Context context) {
+ if (mInstance == null) {
+ mInstance = new SmartDdsSwitchPreferenceController(context);
+ }
+ return mInstance;
+ }
+
+ public void cleanUp() {
+ Log.d(TAG, "Disconnecting ExtTelephonyService");
+ mExtTelephonyManager.disconnectService();
+ mInstance = null;
+ }
+
+ private ServiceCallback mExtTelManagerServiceCallback = new ServiceCallback() {
+ @Override
+ public void onConnected() {
+ Log.d(TAG, "ExtTelephonyService connected");
+ mServiceConnected = true;
+ mClient = mExtTelephonyManager.registerCallback(mPackageName, mCallback);
+ Log.d(TAG, "Client = " + mClient);
+ }
+
+ @Override
+ public void onDisconnected() {
+ Log.d(TAG, "ExtTelephonyService disconnected");
+ mContext.unregisterReceiver(mBroadcastReceiver);
+ mServiceConnected = false;
+ mClient = null;
+ }
+ };
+
+ private ExtPhoneCallbackBase mCallback = new ExtPhoneCallbackBase() {
+ @Override
+ public void setSmartDdsSwitchToggleResponse(Token token, boolean result) throws
+ RemoteException {
+ Log.d(TAG, "setSmartDdsSwitchToggleResponse: token = " + token + " result = " + result);
+ if (result) {
+ mHandler.sendMessage(mHandler.obtainMessage(
+ EVENT_SET_DEFAULT_TOGGLE_STATE_RESPONSE));
+ }
+ }
+ };
+
+ private Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case EVENT_SET_DEFAULT_TOGGLE_STATE_RESPONSE: {
+ Log.d(TAG, "EVENT_SET_DEFAULT_TOGGLE_STATE_RESPONSE");
+ String defaultSummary = mContext.getResources().getString(
+ R.string.smart_dds_switch_summary);
+ updateUi(defaultSummary, true);
+ putSwitchValue(mSwitchEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
+ break;
+ }
+ default:
+ Log.e(TAG, "Unsupported action");
+ }
+ }
+ };
+
+ @Override
+ public String getPreferenceKey() {
+ return Settings.Global.SMART_DDS_SWITCH;
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ mSwitchEnabled = (Boolean) newValue;
+ Log.d(TAG, "onPreferenceChange: isEnabled = " + mSwitchEnabled);
+ // Temporarily update the text and disable the button until the response is received
+ String waitSummary = mContext.getResources().getString(
+ R.string.smart_dds_switch_wait_summary);
+ updateUi(waitSummary, false);
+ if (mServiceConnected && mClient != null) {
+ try {
+ mExtTelephonyManager.setSmartDdsSwitchToggle(mSwitchEnabled, mClient);
+ return true;
+ } catch (Exception e) {
+ Log.e(TAG, "Exception " + e);
+ return false;
+ }
+ } else {
+ Log.e(TAG, "ExtTelephonyManager service not connected");
+ return false;
+ }
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ if (mPreference != null) {
+ final int smartDdsSwitch = getSwitchValue();
+ ((SwitchPreference) mPreference).setChecked(smartDdsSwitch != SETTING_VALUE_OFF);
+ }
+ if (mServiceConnected) {
+ try {
+ mFeatureAvailable = mExtTelephonyManager.isSmartDdsSwitchFeatureAvailable();
+ } catch (Exception e) {
+ Log.e(TAG, "Exception " + e);
+ }
+ Log.d(TAG, "mFeatureAvailable: " + mFeatureAvailable);
+ if (mFeatureAvailable) {
+ String defaultSummary = mContext.getResources().getString(
+ R.string.smart_dds_switch_summary);
+ updateUi(defaultSummary, isAvailable());
+ } else {
+ Log.d(TAG, "Feature unavailable");
+ preference.setVisible(false);
+ }
+ } else {
+ Log.d(TAG, "Service not connected");
+ }
+ }
+
+ private void updateUi(String summary, boolean enable) {
+ Log.d(TAG, "updateUi enable: " + enable);
+ if (mPreference != null) {
+ ((SwitchPreference) mPreference).setVisible(true);
+ ((SwitchPreference) mPreference).setSummary(summary);
+ ((SwitchPreference) mPreference).setEnabled(enable);
+ }
+ }
+
+ @Override
+ public boolean isAvailable() {
+ // Only show the toggle if 1) APM is off and 2) more than one subscription is active
+ SubscriptionManager subscriptionManager = mContext.getSystemService(
+ SubscriptionManager.class);
+ int numActiveSubscriptionInfoCount = subscriptionManager.getActiveSubscriptionInfoCount();
+ Log.d(TAG, "numActiveSubscriptionInfoCount: " + numActiveSubscriptionInfoCount);
+ return !isAirplaneModeOn() && (numActiveSubscriptionInfoCount > 1);
+ }
+
+ private boolean isAirplaneModeOn() {
+ return Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
+ }
+
+ private void putSwitchValue(int state) {
+ Settings.Global.putInt(mContext.getContentResolver(), getPreferenceKey(), state);
+ }
+
+ private int getSwitchValue() {
+ return Settings.Global.getInt(mContext.getContentResolver(), getPreferenceKey(),
+ SETTING_VALUE_OFF);
+ }
+} \ No newline at end of file
diff --git a/src/com/android/settings/development/WifiCoverageExtendPreferenceController.java b/src/com/android/settings/development/WifiCoverageExtendPreferenceController.java
new file mode 100644
index 0000000000..9f974ca4c6
--- /dev/null
+++ b/src/com/android/settings/development/WifiCoverageExtendPreferenceController.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.settings.development;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.SwitchPreference;
+import androidx.preference.Preference;
+
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+public class WifiCoverageExtendPreferenceController extends DeveloperOptionsPreferenceController
+ implements Preference.OnPreferenceChangeListener, PreferenceControllerMixin {
+
+ private static final String WIFI_COVERAGE_EXTEND_KEY = "wifi_coverage_extend";
+
+ private final WifiManager mWifiManager;
+
+ public WifiCoverageExtendPreferenceController(Context context) {
+ super(context);
+
+ mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return WIFI_COVERAGE_EXTEND_KEY;
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ final boolean isEnabled = (Boolean) newValue;
+ mWifiManager.enableWifiCoverageExtendFeature(isEnabled);
+ return true;
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ final boolean enabled = mWifiManager.isWifiCoverageExtendFeatureEnabled();
+ ((SwitchPreference) mPreference).setChecked(enabled);
+
+ }
+
+ @Override
+ protected void onDeveloperOptionsSwitchDisabled() {
+ super.onDeveloperOptionsSwitchDisabled();
+ mWifiManager.enableWifiCoverageExtendFeature(false);
+ ((SwitchPreference) mPreference).setChecked(false);
+ }
+}
diff --git a/src/com/android/settings/development/bluetooth/AbstractBluetoothDialogPreferenceController.java b/src/com/android/settings/development/bluetooth/AbstractBluetoothDialogPreferenceController.java
index d66b8d8dc8..0367fcca22 100644
--- a/src/com/android/settings/development/bluetooth/AbstractBluetoothDialogPreferenceController.java
+++ b/src/com/android/settings/development/bluetooth/AbstractBluetoothDialogPreferenceController.java
@@ -38,7 +38,9 @@ public abstract class AbstractBluetoothDialogPreferenceController extends
private static final String TAG = "AbstractBtDlgCtr";
- protected static final int[] CODEC_TYPES = {BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ protected static final int[] CODEC_TYPES = {BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_TWSP,
+ BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
+ BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_ADAPTIVE,
BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
@@ -162,6 +164,11 @@ public abstract class AbstractBluetoothDialogPreferenceController extends
Log.d(TAG, "Unable to get current codec config. Codec status is null");
return null;
}
+ if (codecStatus.getCodecConfig().getCodecType() >=
+ BluetoothCodecConfig.SOURCE_QVA_CODEC_TYPE_MAX) {
+ Log.d(TAG,"Invalid codec type");
+ return null;
+ }
return codecStatus.getCodecConfig();
}
@@ -219,11 +226,18 @@ public abstract class AbstractBluetoothDialogPreferenceController extends
*/
public void onHDAudioEnabled(boolean enabled) {}
- static int getHighestCodec(BluetoothCodecConfig[] configs) {
+ static int getHighestCodec(BluetoothA2dp bluetoothA2dp, BluetoothDevice activeDevice,
+ BluetoothCodecConfig[] configs) {
if (configs == null) {
Log.d(TAG, "Unable to get highest codec. Configs are empty");
return BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID;
}
+ Log.d(TAG, "CODEC_TYPES len: " + CODEC_TYPES.length + " codec_config len: " + configs.length);
+ // If HD audio is not enabled, SBC is the only one available codec.
+ if (bluetoothA2dp.isOptionalCodecsEnabled(activeDevice)
+ != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) {
+ return BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC;
+ }
for (int i = 0; i < CODEC_TYPES.length; i++) {
for (int j = 0; j < configs.length; j++) {
if ((configs[j].getCodecType() == CODEC_TYPES[i])) {
diff --git a/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreference.java b/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreference.java
index 6a733f3fba..6178ed1937 100644
--- a/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreference.java
+++ b/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreference.java
@@ -22,12 +22,16 @@ import android.widget.RadioGroup;
import com.android.settings.R;
+import android.util.Log;
+
/**
* Dialog preference to set the Bluetooth A2DP config of codec
*/
public class BluetoothCodecDialogPreference extends BaseBluetoothDialogPreference implements
RadioGroup.OnCheckedChangeListener {
+ private static final String TAG = "BtCodecDlgPref";
+
public BluetoothCodecDialogPreference(Context context) {
super(context);
initialize(context);
@@ -60,13 +64,19 @@ public class BluetoothCodecDialogPreference extends BaseBluetoothDialogPreferenc
mRadioButtonIds.add(R.id.bluetooth_audio_codec_aac);
mRadioButtonIds.add(R.id.bluetooth_audio_codec_aptx);
mRadioButtonIds.add(R.id.bluetooth_audio_codec_aptx_hd);
+ mRadioButtonIds.add(R.id.bluetooth_audio_codec_aptx_adaptive);
mRadioButtonIds.add(R.id.bluetooth_audio_codec_ldac);
+ mRadioButtonIds.add(R.id.bluetooth_audio_codec_aptx_twsp);
String[] stringArray = context.getResources().getStringArray(
R.array.bluetooth_a2dp_codec_titles);
+
+ Log.e(TAG, "a2dp_codec_titles array length: " + stringArray.length);
for (int i = 0; i < stringArray.length; i++) {
mRadioButtonStrings.add(stringArray[i]);
}
+
stringArray = context.getResources().getStringArray(R.array.bluetooth_a2dp_codec_summaries);
+ Log.e(TAG, "a2dp_codec_summaries array length: " + stringArray.length);
for (int i = 0; i < stringArray.length; i++) {
mSummaryStrings.add(stringArray[i]);
}
diff --git a/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java b/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java
index 6b243c600f..c8c9241b92 100644
--- a/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java
+++ b/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceController.java
@@ -93,8 +93,9 @@ public class BluetoothCodecDialogPreferenceController extends
int codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
switch (index) {
case 0:
- codecTypeValue = getHighestCodec(getSelectableConfigs(
- mBluetoothA2dp.getActiveDevice()));
+ final BluetoothDevice activeDevice = mBluetoothA2dp.getActiveDevice();
+ codecTypeValue = getHighestCodec(mBluetoothA2dp, activeDevice,
+ getSelectableConfigs(activeDevice));
codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
break;
case 1:
@@ -117,6 +118,14 @@ public class BluetoothCodecDialogPreferenceController extends
codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC;
codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
break;
+ case 6:
+ codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_ADAPTIVE;
+ codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
+ break;
+ case 7:
+ codecTypeValue = BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_TWSP;
+ codecPriorityValue = BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST;
+ break;
default:
break;
}
@@ -147,6 +156,11 @@ public class BluetoothCodecDialogPreferenceController extends
mCallback.onBluetoothCodecChanged();
}
+ @Override
+ public void onHDAudioEnabled(boolean enabled) {
+ writeConfigurationValues(/* index= */ 0);
+ }
+
private List<Integer> getIndexFromConfig(BluetoothCodecConfig[] configs) {
List<Integer> indexArray = new ArrayList<>();
for (int i = 0; i < configs.length; i++) {
@@ -171,9 +185,15 @@ public class BluetoothCodecDialogPreferenceController extends
case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD:
index = 4;
break;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_ADAPTIVE:
+ index = 6;
+ break;
case BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC:
index = 5;
break;
+ case BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_TWSP:
+ index = 7;
+ break;
default:
Log.e(TAG, "Unsupported config:" + config);
break;
diff --git a/src/com/android/settings/development/bluetooth/BluetoothHDAudioPreferenceController.java b/src/com/android/settings/development/bluetooth/BluetoothHDAudioPreferenceController.java
index d4ca4e5795..6481c759f7 100644
--- a/src/com/android/settings/development/bluetooth/BluetoothHDAudioPreferenceController.java
+++ b/src/com/android/settings/development/bluetooth/BluetoothHDAudioPreferenceController.java
@@ -81,6 +81,7 @@ public class BluetoothHDAudioPreferenceController extends AbstractBluetoothPrefe
return true;
}
final boolean enabled = (Boolean) newValue;
+ Log.e(TAG, "onPreferenceChange: " + enabled);
final int prefValue = enabled
? BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED
: BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED;
diff --git a/src/com/android/settings/development/bluetooth/BluetoothQualityDialogPreferenceController.java b/src/com/android/settings/development/bluetooth/BluetoothQualityDialogPreferenceController.java
index 4b38e11977..f4d685733b 100644
--- a/src/com/android/settings/development/bluetooth/BluetoothQualityDialogPreferenceController.java
+++ b/src/com/android/settings/development/bluetooth/BluetoothQualityDialogPreferenceController.java
@@ -105,7 +105,8 @@ public class BluetoothQualityDialogPreferenceController extends
@Override
public void onHDAudioEnabled(boolean enabled) {
- mPreference.setEnabled(false);
+ Log.d(TAG, "onHDAudioEnabled: " + enabled);
+ mPreference.setEnabled(enabled);
}
@VisibleForTesting
diff --git a/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java b/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java
index e6d9dfdbb7..1d89e2e6d6 100644
--- a/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java
+++ b/src/com/android/settings/deviceinfo/DeviceNamePreferenceController.java
@@ -30,6 +30,7 @@ import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
+import com.android.settings.Utils;
import com.android.settings.bluetooth.BluetoothLengthDeviceNameFilter;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.widget.ValidatedEditTextPreference;
@@ -78,6 +79,9 @@ public class DeviceNamePreferenceController extends BasePreferenceController
private void initializeDeviceName() {
mDeviceName = Settings.Global.getString(mContext.getContentResolver(),
Settings.Global.DEVICE_NAME);
+ if (Utils.isSupportCTPA(mContext)) {
+ mDeviceName = Utils.getString(mContext, Utils.KEY_DEVICE_NAME);
+ }
if (mDeviceName == null) {
mDeviceName = Build.MODEL;
}
@@ -138,6 +142,10 @@ public class DeviceNamePreferenceController extends BasePreferenceController
private void setSettingsGlobalDeviceName(String deviceName) {
Settings.Global.putString(mContext.getContentResolver(), Settings.Global.DEVICE_NAME,
deviceName);
+ if (Utils.isSupportCTPA(mContext)) {
+ Settings.Global.putString(mContext.getContentResolver(), Utils.KEY_DEVICE_NAME,
+ deviceName);
+ }
}
private void setBluetoothDeviceName(String deviceName) {
diff --git a/src/com/android/settings/deviceinfo/HardwareInfoPreferenceController.java b/src/com/android/settings/deviceinfo/HardwareInfoPreferenceController.java
index 5f760bfa00..7bc272e8c2 100644
--- a/src/com/android/settings/deviceinfo/HardwareInfoPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/HardwareInfoPreferenceController.java
@@ -22,6 +22,7 @@ import android.util.Log;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
+import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.DeviceInfoUtils;
@@ -49,6 +50,14 @@ public class HardwareInfoPreferenceController extends BasePreferenceController {
@Override
public CharSequence getSummary() {
+ if (Utils.isSupportCTPA(mContext)) {
+ String modelName = Utils.getString(mContext, Utils.KEY_MODEL);
+ if (null == modelName || modelName.isEmpty()) {
+ modelName = getDeviceModel();
+ }
+ return modelName;
+ }
+
return getDeviceModel();
}
diff --git a/src/com/android/settings/deviceinfo/ImsConnector.java b/src/com/android/settings/deviceinfo/ImsConnector.java
new file mode 100644
index 0000000000..f5050be2d8
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/ImsConnector.java
@@ -0,0 +1,106 @@
+/*
+Copyright (c) 2021 The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.settings.deviceinfo;
+
+import android.content.Context;
+import android.telephony.ims.ImsMmTelManager;
+import android.util.Log;
+
+import com.android.ims.FeatureConnector;
+import com.android.ims.ImsException;
+import com.android.ims.ImsManager;
+
+public class ImsConnector implements FeatureConnector.Listener<ImsManager> {
+ private static final String TAG = ImsConnector.class.getSimpleName();
+
+ private Context mContext;
+ private int mSlotId;
+ private FeatureConnector<ImsManager> mConnector;
+ private ImsMmTelManager.RegistrationCallback mRegistrationCallback;
+ private ImsManager mImsManager;
+
+ public ImsConnector(Context context, int slotId,
+ ImsMmTelManager.RegistrationCallback callback) {
+ mContext = context.getApplicationContext();
+ mSlotId = slotId;
+ mRegistrationCallback = callback;
+ mConnector = ImsManager.getConnector(mContext, mSlotId, TAG, this,
+ mContext.getMainExecutor());
+ }
+
+ public void connect() {
+ if (null != mConnector) {
+ mConnector.connect();
+ }
+ }
+
+ public void disconnect() {
+ if (null != mConnector) {
+ mConnector.disconnect();
+ }
+ }
+
+ @Override
+ public void connectionReady(ImsManager manager) throws ImsException {
+ mImsManager = manager;
+ registerListener();
+ }
+
+ @Override
+ public void connectionUnavailable(int reason) {
+ unregisterListener();
+ }
+
+ private void registerListener() {
+ if (null == mImsManager) {
+ Log.e(TAG, "registerListener: mImsManager is null");
+ return;
+ }
+
+ try {
+ mImsManager.addRegistrationCallback(mRegistrationCallback,
+ mContext.getMainExecutor());
+ Log.d(TAG, "registerListener: add callback for mSlotId = " + mSlotId
+ + " mImsManager = " + mImsManager);
+ } catch (ImsException e) {
+ Log.e(TAG, "registerListener: ", e);
+ }
+ }
+
+ private void unregisterListener() {
+ if (null == mImsManager) {
+ Log.e(TAG, "unregisterListener: mImsManager is null");
+ return;
+ }
+
+ mImsManager.removeRegistrationListener(mRegistrationCallback);
+ Log.d(TAG, "unregisterListener: remove ims registration callback for mSlotId = "
+ + mSlotId + " mImsManager = " + mImsManager);
+ }
+} \ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
index 2547dbdf15..1fb31c2500 100644
--- a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java
@@ -16,18 +16,23 @@
package com.android.settings.deviceinfo;
-import static android.content.Context.CLIPBOARD_SERVICE;
-
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsMmTelManager;
import android.text.TextUtils;
+import android.util.Log;
import android.widget.Toast;
import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
@@ -37,9 +42,18 @@ import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.DeviceInfoUtils;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
-public class PhoneNumberPreferenceController extends BasePreferenceController {
+import static android.content.Context.CLIPBOARD_SERVICE;
+import static androidx.lifecycle.Lifecycle.Event;
+
+public class PhoneNumberPreferenceController extends BasePreferenceController
+ implements LifecycleObserver {
+ private static final String TAG = PhoneNumberPreferenceController.class.getSimpleName();
+ // This delay is used to make sure telephony framework has enough time to parse
+ // the phone number from the IMS registration indication message.
+ private static final long DELAY_MILLIS = 500L;
private static final String KEY_PHONE_NUMBER = "phone_number";
private static final String KEY_PREFERENCE_CATEGORY = "basic_info_category";
@@ -47,11 +61,30 @@ public class PhoneNumberPreferenceController extends BasePreferenceController {
private final TelephonyManager mTelephonyManager;
private final SubscriptionManager mSubscriptionManager;
private final List<Preference> mPreferenceList = new ArrayList<>();
+ private HashMap<Integer, ImsConnector> mImsConnectorMap = new HashMap<>();
+ private int mPhoneCount;
+ private Handler mHandler;
+
+ private final ImsMmTelManager.RegistrationCallback mImsRegistrationCallback =
+ new ImsMmTelManager.RegistrationCallback() {
+ @Override
+ public void onRegistered(int imsTransportType) {
+ Log.d(TAG, "onRegistered: imsTransportType=" + imsTransportType);
+ if (mHandler.hasMessagesOrCallbacks()) {
+ Log.d(TAG, "onRegistered: optimize to remove unhandled runnables");
+ mHandler.removeCallbacksAndMessages(null);
+ }
+ mHandler.postDelayed(() -> updateState(null), DELAY_MILLIS);
+ }
+ };
public PhoneNumberPreferenceController(Context context, String key) {
super(context, key);
mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
+ mPhoneCount = mTelephonyManager.getPhoneCount();
+ mHandler = new Handler(Looper.getMainLooper());
+ initImsConnectors();
}
@Override
@@ -161,4 +194,67 @@ public class PhoneNumberPreferenceController extends BasePreferenceController {
protected Preference createNewPreference(Context context) {
return new PhoneNumberSummaryPreference(context);
}
+
+ public void init(Lifecycle lifecycle) {
+ if (null != lifecycle) {
+ lifecycle.addObserver(this);
+ } else {
+ Log.e(TAG, "init: lifecycle is null, invalid param");
+ }
+ }
+
+ @OnLifecycleEvent(Event.ON_RESUME)
+ public void onResume() {
+ connect();
+ }
+
+ @OnLifecycleEvent(Event.ON_PAUSE)
+ public void onPause() {
+ disconnect();
+ mHandler.removeCallbacksAndMessages(null);
+ }
+
+ private void initImsConnectors() {
+ for (int slotId = 0; slotId < mPhoneCount; slotId++) {
+ ImsConnector imsConnector = new ImsConnector(mContext, slotId,
+ mImsRegistrationCallback);
+ mImsConnectorMap.put(Integer.valueOf(slotId), imsConnector);
+ }
+ }
+
+ private void connect() {
+ if (mImsConnectorMap.isEmpty()) {
+ Log.e(TAG, "connect: need init ims connectors");
+ return;
+ }
+
+ int size = mImsConnectorMap.size();
+ for (int index = 0; index < size; index++) {
+ ImsConnector connector = mImsConnectorMap.get(Integer.valueOf(index));
+ if (null != connector) {
+ connector.connect();
+ }
+ }
+ }
+
+ private void disconnect() {
+ if (mImsConnectorMap.isEmpty()) {
+ Log.d(TAG, "disconnect: need do nothing");
+ return;
+ }
+
+ int size = mImsConnectorMap.size();
+ for (int index = 0; index < size; index++) {
+ ImsConnector connector = mImsConnectorMap.get(Integer.valueOf(index));
+ if (null != connector) {
+ connector.disconnect();
+ }
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ mImsConnectorMap.clear();
+ super.finalize();
+ }
}
diff --git a/src/com/android/settings/deviceinfo/SoftwareVersionPreferenceController.java b/src/com/android/settings/deviceinfo/SoftwareVersionPreferenceController.java
new file mode 100755
index 0000000000..79482c0087
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/SoftwareVersionPreferenceController.java
@@ -0,0 +1,73 @@
+/*
+Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.settings.deviceinfo;
+
+import android.content.Context;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.BasePreferenceController;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+public class SoftwareVersionPreferenceController extends BasePreferenceController {
+ private static final String PREF_KEY = "software_version";
+
+ public SoftwareVersionPreferenceController(Context context) {
+ super(context, PREF_KEY);
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ Preference preference = screen.findPreference(PREF_KEY);
+ final CharSequence version = getSummary();
+ preference.setSummary(version);
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ String summary = mContext.getString(R.string.device_info_default);
+ String softwareVersion = Utils.getString(mContext, Utils.KEY_SOFTWARE_VERSION);
+ if (null != softwareVersion && !softwareVersion.isEmpty()) {
+ summary = softwareVersion;
+ }
+ return summary;
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return Utils.isSupportCTPA(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return PREF_KEY;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/settings/deviceinfo/StorageSizePreferenceController.java b/src/com/android/settings/deviceinfo/StorageSizePreferenceController.java
new file mode 100755
index 0000000000..36f078ddcd
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/StorageSizePreferenceController.java
@@ -0,0 +1,93 @@
+/*
+Copyright (c) 2019, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.android.settings.deviceinfo;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.core.AbstractPreferenceController;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+public class StorageSizePreferenceController extends AbstractPreferenceController implements
+ PreferenceControllerMixin {
+ private static final String LOG_TAG = "StorageSizePreferenceController";
+ private final static String KEY_STORAGE_TOTAL_SIZE = "key_storage_total_size";
+
+ public StorageSizePreferenceController(Context context) {
+ super(context);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_STORAGE_TOTAL_SIZE;
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return Utils.isSupportCTPA(mContext);
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ Preference ramSizePreference = screen.findPreference(getPreferenceKey());
+ if (!isAvailable() || null == ramSizePreference || !ramSizePreference.isVisible()) {
+ return;
+ }
+ String ramSize = Utils.getString(mContext, Utils.KEY_RAM_TOTAL_SIZE);
+ Log.d(LOG_TAG, "displayPreference: ramSize = " + ramSize);
+ if (null != ramSize && !ramSize.isEmpty()) {
+ ramSizePreference.setSummary(ramSize);
+ } else {
+ ramSizePreference.setSummary(mContext.getString(R.string.device_info_default));
+ }
+
+ final Preference romSizePreference = createNewPreference(screen.getContext());
+ romSizePreference.setOrder(ramSizePreference.getOrder() + 1);
+ romSizePreference.setKey(KEY_STORAGE_TOTAL_SIZE + 1);
+ screen.addPreference(romSizePreference);
+ romSizePreference.setVisible(true);
+ romSizePreference.setTitle(mContext.getResources().getString(R.string.rom_total_size));
+ String romSize = Utils.getString(mContext, Utils.KEY_ROM_TOTAL_SIZE);
+ Log.d(LOG_TAG, "displayPreference: romSize = " + romSize);
+ if (null != romSize && !romSize.isEmpty()) {
+ romSizePreference.setSummary(romSize);
+ } else {
+ romSizePreference.setSummary(mContext.getString(R.string.device_info_default));
+ }
+ }
+
+ private Preference createNewPreference(Context context) {
+ return new Preference(context);
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
index ea4a2fd29e..10ea565d6b 100644..100755
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
@@ -93,21 +93,24 @@ public class StorageWizardFormatProgress extends StorageWizardBase {
storage.partitionPrivate(activity.mDisk.getId());
publishProgress(40);
- final VolumeInfo privateVol = activity.findFirstVolume(TYPE_PRIVATE, 25);
+ final VolumeInfo privateVol = activity.findFirstVolume(TYPE_PRIVATE, 50);
final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
- storage.benchmark(privateVol.getId(), new IVoldTaskListener.Stub() {
- @Override
- public void onStatus(int status, PersistableBundle extras) {
- // Map benchmark 0-100% progress onto 40-80%
- publishProgress(40 + ((status * 40) / 100));
- }
-
- @Override
- public void onFinished(int status, PersistableBundle extras) {
- result.complete(extras);
- }
- });
- mPrivateBench = result.get(60, TimeUnit.SECONDS).getLong("run", Long.MAX_VALUE);
+ if(null != privateVol) {
+ storage.benchmark(privateVol.getId(), new IVoldTaskListener.Stub() {
+ @Override
+ public void onStatus(int status, PersistableBundle extras) {
+ // Map benchmark 0-100% progress onto 40-80%
+ publishProgress(40 + ((status * 40) / 100));
+ }
+
+ @Override
+ public void onFinished(int status, PersistableBundle extras) {
+ result.complete(extras);
+ }
+ });
+ mPrivateBench = result.get(60, TimeUnit.SECONDS).getLong("run",
+ Long.MAX_VALUE);
+ }
// If we just adopted the device that had been providing
// physical storage, then automatically move storage to the
diff --git a/src/com/android/settings/deviceinfo/WifiMacAddressPreferenceController.java b/src/com/android/settings/deviceinfo/WifiMacAddressPreferenceController.java
index c7005966c4..8b0b4ec4c1 100644
--- a/src/com/android/settings/deviceinfo/WifiMacAddressPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/WifiMacAddressPreferenceController.java
@@ -17,11 +17,16 @@
package com.android.settings.deviceinfo;
import android.content.Context;
+import android.net.wifi.WifiInfo;
+import android.util.Log;
import com.android.settings.R;
+import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.deviceinfo.AbstractWifiMacAddressPreferenceController;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
/**
* Concrete subclass of WIFI MAC address preference controller
@@ -37,5 +42,25 @@ public class WifiMacAddressPreferenceController extends AbstractWifiMacAddressPr
return mContext.getResources().getBoolean(R.bool.config_show_wifi_mac_address);
}
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ if (Utils.isSupportCTPA(mContext)) {
+ Preference macAddressPreference = screen.findPreference(getPreferenceKey());
+ CharSequence oldValue = macAddressPreference.getSummary();
+ String macAddress = Utils.getString(mContext, Utils.KEY_WIFI_MAC_ADDRESS);
+ String unAvailable = mContext.getString(
+ com.android.settingslib.R.string.status_unavailable);
+ Log.d(TAG, "displayPreference: macAddress = " + macAddress
+ + " oldValue = " + oldValue + " unAvailable = " + unAvailable);
+ if (null == macAddress || macAddress.isEmpty()) {
+ macAddress = unAvailable;
+ }
+ if (null != oldValue && (WifiInfo.DEFAULT_MAC_ADDRESS.equals(oldValue) ||
+ unAvailable.equals(oldValue))) {
+ macAddressPreference.setSummary(macAddress);
+ }
+ }
+ }
// This space intentionally left blank
}
diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
index 4af5d79c37..dcfb0e8efe 100644
--- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
+++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java
@@ -23,6 +23,7 @@ import android.content.Intent;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.UserManager;
+import android.util.Log;
import android.view.View;
import com.android.settings.R;
@@ -35,8 +36,11 @@ import com.android.settings.deviceinfo.FccEquipmentIdPreferenceController;
import com.android.settings.deviceinfo.FeedbackPreferenceController;
import com.android.settings.deviceinfo.IpAddressPreferenceController;
import com.android.settings.deviceinfo.ManualPreferenceController;
+import com.android.settings.deviceinfo.PhoneNumberPreferenceController;
import com.android.settings.deviceinfo.RegulatoryInfoPreferenceController;
import com.android.settings.deviceinfo.SafetyInfoPreferenceController;
+import com.android.settings.deviceinfo.SoftwareVersionPreferenceController;
+import com.android.settings.deviceinfo.StorageSizePreferenceController;
import com.android.settings.deviceinfo.UptimePreferenceController;
import com.android.settings.deviceinfo.WifiMacAddressPreferenceController;
import com.android.settings.deviceinfo.imei.ImeiInfoPreferenceController;
@@ -51,6 +55,12 @@ import com.android.settingslib.widget.LayoutPreference;
import java.util.ArrayList;
import java.util.List;
+import android.content.BroadcastReceiver;
+import android.content.IntentFilter;
+
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.TelephonyIntents;
+
@SearchIndexable
public class MyDeviceInfoFragment extends DashboardFragment
implements DeviceNamePreferenceController.DeviceNamePreferenceHost {
@@ -58,6 +68,17 @@ public class MyDeviceInfoFragment extends DashboardFragment
private static final String LOG_TAG = "MyDeviceInfoFragment";
private static final String KEY_MY_DEVICE_INFO_HEADER = "my_device_info_header";
+ private final BroadcastReceiver mSimStateReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
+ String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
+ Log.d(LOG_TAG, "Received ACTION_SIM_STATE_CHANGED: " + state);
+ updatePreferenceStates();
+ }
+ }
+ };
+
private BuildNumberPreferenceController mBuildNumberPreferenceController;
@Override
@@ -77,6 +98,7 @@ public class MyDeviceInfoFragment extends DashboardFragment
use(DeviceNamePreferenceController.class).setHost(this /* parent */);
mBuildNumberPreferenceController = use(BuildNumberPreferenceController.class);
mBuildNumberPreferenceController.setHost(this /* parent */);
+ use(PhoneNumberPreferenceController.class).init(getSettingsLifecycle());
}
@Override
@@ -86,6 +108,29 @@ public class MyDeviceInfoFragment extends DashboardFragment
}
@Override
+ public void onPause() {
+ super.onPause();
+ Context context = getContext();
+ if (context != null) {
+ context.unregisterReceiver(mSimStateReceiver);
+ } else {
+ Log.i(LOG_TAG, "context already null, not unregistering SimStateReceiver");
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Context context = getContext();
+ if (context != null) {
+ context.registerReceiver(mSimStateReceiver,
+ new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
+ } else {
+ Log.i(LOG_TAG, "context is null, not registering SimStateReceiver");
+ }
+ }
+
+ @Override
protected String getLogTag() {
return LOG_TAG;
}
@@ -113,6 +158,8 @@ public class MyDeviceInfoFragment extends DashboardFragment
controllers.add(new FeedbackPreferenceController(fragment, context));
controllers.add(new FccEquipmentIdPreferenceController(context));
controllers.add(new UptimePreferenceController(context, lifecycle));
+ controllers.add(new SoftwareVersionPreferenceController(context));
+ controllers.add(new StorageSizePreferenceController(context));
return controllers;
}
diff --git a/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceController.java b/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceController.java
index dd3d560282..1507ddc80b 100644
--- a/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/firmwareversion/BasebandVersionPreferenceController.java
@@ -29,9 +29,11 @@ public class BasebandVersionPreferenceController extends BasePreferenceControlle
@VisibleForTesting
static final String BASEBAND_PROPERTY = "gsm.version.baseband";
+ private final Context mContext;
public BasebandVersionPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
+ mContext = context;
}
@Override
@@ -41,6 +43,16 @@ public class BasebandVersionPreferenceController extends BasePreferenceControlle
@Override
public CharSequence getSummary() {
+ if (Utils.isSupportCTPA(mContext.getApplicationContext())) {
+ String baseBands = SystemProperties.get(BASEBAND_PROPERTY,
+ mContext.getString(R.string.device_info_default));
+ if (null != baseBands) {
+ String[] baseBandArray = baseBands.split(",");
+ if ((baseBandArray != null) && (baseBandArray.length > 0)) {
+ return baseBandArray[0];
+ }
+ }
+ }
return SystemProperties.get(BASEBAND_PROPERTY,
mContext.getString(R.string.device_info_default));
}
diff --git a/src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java
index e5fd3daa94..9d00b6667e 100644
--- a/src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/hardwareinfo/HardwareRevisionPreferenceController.java
@@ -21,6 +21,7 @@ import android.os.SystemProperties;
import android.text.TextUtils;
import com.android.settings.R;
+import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.slices.Sliceable;
@@ -49,6 +50,12 @@ public class HardwareRevisionPreferenceController extends BasePreferenceControll
@Override
public CharSequence getSummary() {
+ if (Utils.isSupportCTPA(mContext)) {
+ String hardwareVersion = Utils.getString(mContext, Utils.KEY_HARDWARE_VERSION);
+ if (null != hardwareVersion && !hardwareVersion.isEmpty()) {
+ return hardwareVersion;
+ }
+ }
return SystemProperties.get("ro.boot.hardware.revision");
}
}
diff --git a/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java b/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java
index 1ae6b4007b..db93f2a2b7 100644
--- a/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java
+++ b/src/com/android/settings/deviceinfo/imei/ImeiInfoDialogController.java
@@ -21,12 +21,16 @@ import android.content.res.Resources;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
+import com.android.settings.network.telephony.TelephonyUtils;
+
+import com.qti.extphone.QtiImeiInfo;
public class ImeiInfoDialogController {
@@ -52,6 +56,7 @@ public class ImeiInfoDialogController {
private final TelephonyManager mTelephonyManager;
private final SubscriptionInfo mSubscriptionInfo;
private final int mSlotId;
+ private QtiImeiInfo mQtiImeiInfo[];
public ImeiInfoDialogController(@NonNull ImeiInfoDialogFragment dialog, int slotId) {
mDialog = dialog;
@@ -68,6 +73,23 @@ public class ImeiInfoDialogController {
} else {
mTelephonyManager = null;
}
+ mQtiImeiInfo = TelephonyUtils.getImeiInfo();
+ }
+
+ private String getImei(int slot) {
+ String imei = null;
+ if (mQtiImeiInfo != null) {
+ for (int i = 0; i < mQtiImeiInfo.length; i++) {
+ if (mQtiImeiInfo[i].getSlotId() == slot) {
+ imei = mQtiImeiInfo[i].getImei();
+ break;
+ }
+ }
+ }
+ if (TextUtils.isEmpty(imei)) {
+ imei = mTelephonyManager.getImei(slot);
+ }
+ return imei;
}
/**
@@ -103,7 +125,7 @@ public class ImeiInfoDialogController {
if ((mSubscriptionInfo != null && isCdmaLteEnabled()) ||
(mSubscriptionInfo == null && isSimPresent(mSlotId))) {
// Show IMEI for LTE device
- mDialog.setText(ID_IMEI_VALUE, mTelephonyManager.getImei(mSlotId));
+ mDialog.setText(ID_IMEI_VALUE, getImei(mSlotId));
mDialog.setText(ID_IMEI_SV_VALUE,
mTelephonyManager.getDeviceSoftwareVersion(mSlotId));
} else {
@@ -113,7 +135,7 @@ public class ImeiInfoDialogController {
}
private void updateDialogForGsmPhone() {
- mDialog.setText(ID_IMEI_VALUE, mTelephonyManager.getImei(mSlotId));
+ mDialog.setText(ID_IMEI_VALUE, getImei(mSlotId));
mDialog.setText(ID_IMEI_SV_VALUE,
mTelephonyManager.getDeviceSoftwareVersion(mSlotId));
// device is not CDMA, do not display CDMA features
diff --git a/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceController.java b/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceController.java
index e0bff6d51a..f45640fe02 100644
--- a/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/imei/ImeiInfoPreferenceController.java
@@ -23,6 +23,8 @@ import android.os.UserManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
@@ -33,8 +35,11 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.deviceinfo.PhoneNumberSummaryPreference;
+import com.android.settings.network.telephony.TelephonyUtils;
import com.android.settings.slices.Sliceable;
-import com.android.settingslib.Utils;
+import com.android.settings.Utils;
+
+import com.qti.extphone.QtiImeiInfo;
import java.util.ArrayList;
import java.util.List;
@@ -45,16 +50,21 @@ import java.util.List;
public class ImeiInfoPreferenceController extends BasePreferenceController {
private static final String KEY_PREFERENCE_CATEGORY = "device_detail_category";
+ private static final String TAG = "ImeiInfoPreferenceController";
private final boolean mIsMultiSim;
private final TelephonyManager mTelephonyManager;
private final List<Preference> mPreferenceList = new ArrayList<>();
private Fragment mFragment;
+ private QtiImeiInfo mQtiImeiInfo[];
public ImeiInfoPreferenceController(Context context, String key) {
super(context, key);
mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
mIsMultiSim = mTelephonyManager.getPhoneCount() > 1;
+ if (mIsMultiSim) {
+ TelephonyUtils.connectExtTelephonyService(context);
+ }
}
public void setHost(Fragment fragment) {
@@ -81,6 +91,54 @@ public class ImeiInfoPreferenceController extends BasePreferenceController {
mPreferenceList.add(multiSimPreference);
updatePreference(multiSimPreference, simSlotNumber);
}
+
+ final int phoneCount = mTelephonyManager.getPhoneCount();
+ if (Utils.isSupportCTPA(mContext) && phoneCount >= 2) {
+ final int slot0PhoneType = mTelephonyManager.getCurrentPhoneTypeForSlot(0);
+ final int slot1PhoneType = mTelephonyManager.getCurrentPhoneTypeForSlot(1);
+ if (PHONE_TYPE_CDMA != slot0PhoneType && PHONE_TYPE_CDMA != slot1PhoneType) {
+ addPreferenceNotInList(screen, 0, imeiPreferenceOrder + phoneCount,
+ getPreferenceKey() + phoneCount, true);
+ } else if (PHONE_TYPE_CDMA == slot0PhoneType){
+ addPreferenceNotInList(screen, 0, imeiPreferenceOrder + phoneCount,
+ getPreferenceKey() + phoneCount, false);
+ } else if (PHONE_TYPE_CDMA == slot1PhoneType) {
+ addPreferenceNotInList(screen, 1, imeiPreferenceOrder + phoneCount,
+ getPreferenceKey() + phoneCount, false);
+ }
+ }
+ }
+
+ private void addPreferenceNotInList(PreferenceScreen screen, int slotNumber, int order,
+ String key, boolean isCDMAPhone) {
+ final Preference multiSimPreference = createNewPreference(screen.getContext());
+ multiSimPreference.setOrder(order);
+ multiSimPreference.setKey(key);
+ final PreferenceCategory category = screen.findPreference(KEY_PREFERENCE_CATEGORY);
+ category.addPreference(multiSimPreference);
+ if (isCDMAPhone) {
+ multiSimPreference.setTitle(getTitleForCdmaPhone(slotNumber));
+ multiSimPreference.setSummary(mTelephonyManager.getMeid(slotNumber));
+ } else {
+ multiSimPreference.setTitle(getTitleForGsmPhone(slotNumber));
+ multiSimPreference.setSummary(getImei(slotNumber));
+ }
+ }
+
+ private void addPreference(PreferenceScreen screen, int slotNumber, int order,
+ String key, boolean isCDMAPhone) {
+ final Preference multiSimPreference = createNewPreference(screen.getContext());
+ multiSimPreference.setOrder(order);
+ multiSimPreference.setKey(key);
+ screen.addPreference(multiSimPreference);
+ mPreferenceList.add(multiSimPreference);
+ if (isCDMAPhone) {
+ multiSimPreference.setTitle(getTitleForCdmaPhone(slotNumber));
+ multiSimPreference.setSummary(mTelephonyManager.getMeid(slotNumber));
+ } else {
+ multiSimPreference.setTitle(getTitleForGsmPhone(slotNumber));
+ multiSimPreference.setSummary(getImei(slotNumber));
+ }
}
@Override
@@ -88,6 +146,8 @@ public class ImeiInfoPreferenceController extends BasePreferenceController {
if (preference == null) {
return;
}
+ Log.d(TAG, "updateState");
+ mQtiImeiInfo = TelephonyUtils.getImeiInfo();
int size = mPreferenceList.size();
for (int i = 0; i < size; i++) {
Preference pref = mPreferenceList.get(i);
@@ -102,8 +162,14 @@ public class ImeiInfoPreferenceController extends BasePreferenceController {
private CharSequence getSummary(int simSlot) {
final int phoneType = getPhoneType(simSlot);
+ if (Utils.isSupportCTPA(mContext)) {
+ // only can obtain the MEID by slot 0
+ if (PHONE_TYPE_CDMA == phoneType) {
+ simSlot = 0;
+ }
+ }
return phoneType == PHONE_TYPE_CDMA ? mTelephonyManager.getMeid(simSlot)
- : mTelephonyManager.getImei(simSlot);
+ : getImei(simSlot);
}
@Override
@@ -113,6 +179,10 @@ public class ImeiInfoPreferenceController extends BasePreferenceController {
return false;
}
+ if (Utils.isSupportCTPA(mContext)) {
+ return true;
+ }
+
ImeiInfoDialogFragment.show(mFragment, simSlot, preference.getTitle().toString());
return true;
}
@@ -138,9 +208,49 @@ public class ImeiInfoPreferenceController extends BasePreferenceController {
preference.setSummary(getSummary(simSlot));
}
+ private boolean isPrimaryImeiSlot(int slot) {
+ boolean primaryImeiSlotStatus = false;
+ if (mQtiImeiInfo == null) {
+ mQtiImeiInfo = TelephonyUtils.getImeiInfo();
+ }
+ if (mQtiImeiInfo != null) {
+ for (int i = 0; i < mQtiImeiInfo.length; i++) {
+ if (null != mQtiImeiInfo[i] && mQtiImeiInfo[i].getSlotId() == slot &&
+ mQtiImeiInfo[i].getImeiType() == QtiImeiInfo.IMEI_TYPE_PRIMARY) {
+ primaryImeiSlotStatus = true;
+ break;
+ }
+ }
+ }
+ return primaryImeiSlotStatus;
+ }
+
+ private String getImei(int slot) {
+ String imei = null;
+ if (mQtiImeiInfo == null) {
+ mQtiImeiInfo = TelephonyUtils.getImeiInfo();
+ }
+ if (mQtiImeiInfo != null) {
+ for (int i = 0; i < mQtiImeiInfo.length; i++) {
+ if (mQtiImeiInfo[i].getSlotId() == slot) {
+ imei = mQtiImeiInfo[i].getImei();
+ break;
+ }
+ }
+ }
+ if (TextUtils.isEmpty(imei)) {
+ imei = mTelephonyManager.getImei(slot);
+ }
+ return imei;
+ }
+
private CharSequence getTitleForGsmPhone(int simSlot) {
- return mIsMultiSim ? mContext.getString(R.string.imei_multi_sim, simSlot + 1)
+ CharSequence title = mIsMultiSim ? mContext.getString(R.string.imei_multi_sim, simSlot + 1)
: mContext.getString(R.string.status_imei);
+ if (mIsMultiSim && isPrimaryImeiSlot(simSlot)) {
+ title += " (Primary)";
+ }
+ return title;
}
private CharSequence getTitleForCdmaPhone(int simSlot) {
@@ -155,6 +265,9 @@ public class ImeiInfoPreferenceController extends BasePreferenceController {
}
private int getPhoneType(int slotIndex) {
+ if (Utils.isSupportCTPA(mContext)) {
+ return mTelephonyManager.getCurrentPhoneTypeForSlot(slotIndex);
+ }
SubscriptionInfo subInfo = SubscriptionManager.from(mContext)
.getActiveSubscriptionInfoForSimSlotIndex(slotIndex);
return mTelephonyManager.getCurrentPhoneType(subInfo != null ? subInfo.getSubscriptionId()
diff --git a/src/com/android/settings/display/BrightnessLevelPreferenceController.java b/src/com/android/settings/display/BrightnessLevelPreferenceController.java
index de4fe25bc9..f949614d1a 100644..100755
--- a/src/com/android/settings/display/BrightnessLevelPreferenceController.java
+++ b/src/com/android/settings/display/BrightnessLevelPreferenceController.java
@@ -104,8 +104,8 @@ public class BrightnessLevelPreferenceController extends AbstractPreferenceContr
if (lifecycle != null) {
lifecycle.addObserver(this);
}
- final PowerManager powerManager = context.getSystemService(PowerManager.class);
+ final PowerManager powerManager = context.getSystemService(PowerManager.class);
mMinVrBrightness = powerManager.getBrightnessConstraint(
PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM_VR);
mMaxVrBrightness = powerManager.getBrightnessConstraint(
diff --git a/src/com/android/settings/location/AgpsPreferenceController.java b/src/com/android/settings/location/AgpsPreferenceController.java
new file mode 100755
index 0000000000..1504668faa
--- /dev/null
+++ b/src/com/android/settings/location/AgpsPreferenceController.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 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.location;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.CheckBoxPreference;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+
+public class AgpsPreferenceController extends LocationBasePreferenceController {
+ private static final String KEY_ASSISTED_GPS = "assisted_gps";
+
+ private CheckBoxPreference mAgpsPreference;
+
+ public AgpsPreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_ASSISTED_GPS;
+ }
+
+ @AvailabilityStatus
+ public int getAvailabilityStatus() {
+ return mContext.getResources().getBoolean(R.bool.config_agps_enabled)
+ ? AVAILABLE
+ : UNSUPPORTED_ON_DEVICE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mAgpsPreference =
+ (CheckBoxPreference) screen.findPreference(KEY_ASSISTED_GPS);
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ if (mAgpsPreference != null) {
+ mAgpsPreference.setChecked(Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.ASSISTED_GPS_ENABLED, 0) == 1);
+ }
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (KEY_ASSISTED_GPS.equals(preference.getKey())) {
+ final ContentResolver cr = mContext.getContentResolver();
+ final boolean switchState = mAgpsPreference.isChecked();
+ Settings.Global.putInt(cr, Settings.Global.ASSISTED_GPS_ENABLED,
+ switchState ? 1 : 0);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onLocationModeChanged(int mode, boolean restricted) {}
+}
diff --git a/src/com/android/settings/location/AppSettingsInjector.java b/src/com/android/settings/location/AppSettingsInjector.java
index 7bea99931e..899d4ef9cb 100644
--- a/src/com/android/settings/location/AppSettingsInjector.java
+++ b/src/com/android/settings/location/AppSettingsInjector.java
@@ -19,9 +19,19 @@ package com.android.settings.location;
import android.content.Context;
import android.content.Intent;
import android.text.TextUtils;
+import android.content.pm.ResolveInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.os.UserHandle;
+
+import android.location.SettingInjectorService;
import androidx.preference.Preference;
+import java.io.IOException;
+
+import org.xmlpull.v1.XmlPullParserException;
+
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.RestrictedAppPreference;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
@@ -43,11 +53,30 @@ public class AppSettingsInjector extends SettingsInjector {
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
}
+ /**
+ * Returns the settings parsed from the attributes of the
+ * {@link SettingInjectorService#META_DATA_NAME} tag, or null.
+ *
+ * Duplicates some code from {@link android.content.pm.RegisteredServicesCache}.
+ */
+ @Override
+ protected InjectedSetting parseServiceInfo(ResolveInfo service, UserHandle userHandle,
+ PackageManager pm) throws XmlPullParserException, IOException {
+ InjectedSetting res = super.parseServiceInfo(service, userHandle, pm);
+ ServiceInfo si = service.serviceInfo;
+
+ if ((null != res) && (!DimmableIZatIconPreference.showIzat(mContext, si.packageName))) {
+ res = null;
+ }
+
+ return res;
+ }
+
@Override
protected Preference createPreference(Context prefContext, InjectedSetting setting) {
return TextUtils.isEmpty(setting.userRestriction)
- ? new AppPreference(prefContext)
- : new RestrictedAppPreference(prefContext, setting.userRestriction);
+ ? DimmableIZatIconPreference.getAppPreference(prefContext, setting)
+ : DimmableIZatIconPreference.getRestrictedAppPreference(prefContext, setting);
}
@Override
diff --git a/src/com/android/settings/location/DimmableIZatIconPreference.java b/src/com/android/settings/location/DimmableIZatIconPreference.java
new file mode 100644
index 0000000000..53723e663b
--- /dev/null
+++ b/src/com/android/settings/location/DimmableIZatIconPreference.java
@@ -0,0 +1,227 @@
+/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of The Linux Foundation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+package com.android.settings.location;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import androidx.preference.PreferenceViewHolder;
+import com.android.settingslib.location.InjectedSetting;
+import android.util.Log;
+import com.android.settingslib.widget.AppPreference;
+import com.android.settings.widget.RestrictedAppPreference;
+import dalvik.system.DexClassLoader;
+import java.lang.ClassNotFoundException;
+import java.lang.ExceptionInInitializerError;
+import java.lang.IllegalAccessException;
+import java.lang.IllegalArgumentException;
+import java.lang.LinkageError;
+import java.lang.NoSuchFieldException;
+import java.lang.NoSuchMethodException;
+import java.lang.NullPointerException;
+import java.lang.SecurityException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import com.android.settings.R;
+
+public class DimmableIZatIconPreference {
+ private static final String TAG = "DimmableIZatIconPreference";
+ private static Class mXtProxyClz;
+ private static Class mNotifierClz;
+ private static Method mGetXtProxyMethod;
+ private static Method mGetConsentMethod;
+ private static Method mShowIzatMethod;
+ private static String mIzatPackage;
+ private static DexClassLoader mLoader;
+
+ private static void load(Context context) {
+ if (mLoader == null) {
+ try {
+ if (mXtProxyClz == null || mNotifierClz == null) {
+ mLoader = new DexClassLoader("/system_ext/framework/izat.xt.srv.jar",
+ context.getFilesDir().getAbsolutePath(),
+ null,
+ ClassLoader.getSystemClassLoader());
+ mXtProxyClz = Class.forName("com.qti.izat.XTProxy",
+ true,
+ mLoader);
+ mNotifierClz = Class.forName("com.qti.izat.XTProxy$Notifier",
+ true,
+ mLoader);
+ mIzatPackage = (String)mXtProxyClz.getField("IZAT_XT_PACKAGE").get(null);
+ mGetXtProxyMethod = mXtProxyClz.getMethod("getXTProxy",
+ Context.class,
+ mNotifierClz);
+ mGetConsentMethod = mXtProxyClz.getMethod("getUserConsent");
+ mShowIzatMethod = mXtProxyClz.getMethod("showIzat",
+ Context.class,
+ String.class);
+ }
+ } catch (NoSuchMethodException | NullPointerException | SecurityException |
+ NoSuchFieldException | LinkageError | IllegalAccessException |
+ ClassNotFoundException e) {
+ mXtProxyClz = null;
+ mNotifierClz = null;
+ mIzatPackage = null;
+ mGetXtProxyMethod = null;
+ mGetConsentMethod = null;
+ mShowIzatMethod = null;
+ e.printStackTrace();
+ }
+ }
+ }
+
+ static boolean showIzat(Context context, String packageName) {
+ load(context);
+ boolean show = true;
+ try {
+ if (mShowIzatMethod != null) {
+ show = (Boolean)mShowIzatMethod.invoke(null, context, packageName);
+ }
+ } catch (IllegalAccessException | IllegalArgumentException |
+ InvocationTargetException | ExceptionInInitializerError e) {
+ e.printStackTrace();
+ }
+ return show;
+ }
+
+ private static boolean isIzatPackage(Context context, InjectedSetting info) {
+ return (mIzatPackage != null && mIzatPackage.equals(info.packageName));
+ }
+
+ private static final int ICON_ALPHA_ENABLED = 255;
+ private static final int ICON_ALPHA_DISABLED = 102;
+
+ private static void dimIcon(AppPreference pref, boolean dimmed) {
+ Drawable icon = pref.getIcon();
+ if (icon != null) {
+ icon.mutate().setAlpha(dimmed ? ICON_ALPHA_DISABLED : ICON_ALPHA_ENABLED);
+ pref.setIcon(icon);
+ }
+ }
+
+ private static class IZatAppPreference extends AppPreference {
+ private boolean mChecked;
+ private Context mContext;
+ private IZatAppPreference(Context context) {
+ super(context);
+ mContext = context;
+ Object notifier = Proxy.newProxyInstance(mLoader,
+ new Class[] { mNotifierClz },
+ new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ if (method.getName().equals("userConsentNotify") &&
+ args[0] != null && args[0] instanceof Boolean) {
+ boolean consent = (Boolean)args[0];
+ if (mChecked != consent) {
+ mChecked = consent;
+ dimIcon(IZatAppPreference.this, !isEnabled() || !mChecked);
+ }
+ }
+ return null;
+ }});
+
+ try {
+ Object xt = mGetXtProxyMethod.invoke(null, context, notifier);
+ mChecked = (Boolean)mGetConsentMethod.invoke(xt);
+ } catch (IllegalAccessException | IllegalArgumentException |
+ InvocationTargetException | ExceptionInInitializerError e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ int resId;
+ if (!isEnabled() || !mChecked) {
+ resId = R.string.notification_toggle_off;
+ } else {
+ resId = R.string.notification_toggle_on;
+ }
+ return mContext.getString(resId);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder view) {
+ super.onBindViewHolder(view);
+ DimmableIZatIconPreference.dimIcon(this, !isEnabled() || !mChecked);
+ }
+ }
+
+ private static class IZatRestrictedAppPreference extends RestrictedAppPreference {
+ private boolean mChecked;
+ private IZatRestrictedAppPreference(Context context, String userRestriction) {
+ super(context, userRestriction);
+ Object notifier = Proxy.newProxyInstance(mLoader,
+ new Class[] { mNotifierClz },
+ new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ if (method.getName().equals("userConsentNotify") &&
+ args[0] != null && args[0] instanceof Boolean) {
+ boolean consent = (Boolean)args[0];
+ if (mChecked != consent) {
+ mChecked = consent;
+ dimIcon(IZatRestrictedAppPreference.this, !isEnabled() || !mChecked);
+ }
+ }
+ return null;
+ }});
+
+ try {
+ Object xt = mGetXtProxyMethod.invoke(null, context, notifier);
+ mChecked = (Boolean)mGetConsentMethod.invoke(xt);
+ } catch (IllegalAccessException | IllegalArgumentException |
+ InvocationTargetException | ExceptionInInitializerError e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder view) {
+ super.onBindViewHolder(view);
+ DimmableIZatIconPreference.dimIcon(this, !isEnabled() || !mChecked);
+ }
+ }
+
+ static AppPreference getAppPreference(Context context, InjectedSetting info) {
+ return isIzatPackage(context, info) ?
+ new IZatAppPreference(context) :
+ new AppPreference(context);
+ }
+
+ static RestrictedAppPreference getRestrictedAppPreference(Context context, InjectedSetting info) {
+ return isIzatPackage(context, info) ?
+ new IZatRestrictedAppPreference(context, info.userRestriction) :
+ new RestrictedAppPreference(context, info.userRestriction);
+ }
+}
diff --git a/src/com/android/settings/location/LocationSettings.java b/src/com/android/settings/location/LocationSettings.java
index 8f9787b08a..62685d892c 100644
--- a/src/com/android/settings/location/LocationSettings.java
+++ b/src/com/android/settings/location/LocationSettings.java
@@ -90,6 +90,7 @@ public class LocationSettings extends DashboardFragment implements
use(RecentLocationAccessSeeAllButtonPreferenceController.class).init(this);
use(LocationForWorkPreferenceController.class).init(this);
use(LocationSettingsFooterPreferenceController.class).init(this);
+ use(AgpsPreferenceController.class).init(this);
}
@Override
diff --git a/src/com/android/settings/network/AirplaneModePreferenceController.java b/src/com/android/settings/network/AirplaneModePreferenceController.java
index e74f3ae979..a2c56b53b7 100644
--- a/src/com/android/settings/network/AirplaneModePreferenceController.java
+++ b/src/com/android/settings/network/AirplaneModePreferenceController.java
@@ -17,12 +17,17 @@ package com.android.settings.network;
import static android.provider.SettingsSlicesContract.KEY_AIRPLANE_MODE;
+import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.database.ContentObserver;
import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
import android.provider.SettingsSlicesContract;
+import android.provider.Settings;
import android.telephony.TelephonyManager;
import androidx.annotation.VisibleForTesting;
@@ -34,16 +39,22 @@ import androidx.preference.SwitchPreference;
import com.android.settings.AirplaneModeEnabler;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
+import com.android.settings.slices.SliceBackgroundWorker;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnDestroy;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
+import com.qti.extphone.ExtTelephonyManager;
+
+import java.io.IOException;
+
public class AirplaneModePreferenceController extends TogglePreferenceController
implements LifecycleObserver, OnStart, OnStop, OnDestroy,
AirplaneModeEnabler.OnAirplaneModeChangedListener {
public static final int REQUEST_CODE_EXIT_ECM = 1;
+ public static final int REQUEST_CODE_EXIT_SCBM = 2;
/**
* Uri for Airplane mode Slice.
@@ -79,17 +90,25 @@ public class AirplaneModePreferenceController extends TogglePreferenceController
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
- if (KEY_AIRPLANE_MODE.equals(preference.getKey())
- && mAirplaneModeEnabler.isInEcmMode()) {
- // In ECM mode launch ECM app dialog
- if (mFragment != null) {
- mFragment.startActivityForResult(
- new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null),
- REQUEST_CODE_EXIT_ECM);
+ if (KEY_AIRPLANE_MODE.equals(preference.getKey())) {
+ if(mAirplaneModeEnabler.isInEcmMode()) {
+ // In ECM mode launch ECM app dialog
+ if (mFragment != null) {
+ mFragment.startActivityForResult(
+ new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null),
+ REQUEST_CODE_EXIT_ECM);
+ }
+ return true;
+ } else if(mAirplaneModeEnabler.isInScbm()) {
+ // In SCBM mode launch SCBM app dialog
+ if (mFragment != null) {
+ mFragment.startActivityForResult(
+ new Intent(ExtTelephonyManager.ACTION_SHOW_NOTICE_SCM_BLOCK_OTHERS,
+ null), REQUEST_CODE_EXIT_SCBM);
+ }
+ return true;
}
- return true;
}
-
return false;
}
@@ -149,7 +168,12 @@ public class AirplaneModePreferenceController extends TogglePreferenceController
if (requestCode == REQUEST_CODE_EXIT_ECM) {
final boolean isChoiceYes = data.getBooleanExtra(EXIT_ECM_RESULT, false);
// Set Airplane mode based on the return value and checkbox state
- mAirplaneModeEnabler.setAirplaneModeInECM(isChoiceYes,
+ mAirplaneModeEnabler.setAirplaneModeInEmergencyMode(isChoiceYes,
+ mAirplaneModePreference.isChecked());
+ } else if (requestCode == REQUEST_CODE_EXIT_SCBM) {
+ final boolean isChoiceYes = resultCode == Activity.RESULT_OK;
+ // Set Airplane mode based on the return value and checkbox state
+ mAirplaneModeEnabler.setAirplaneModeInEmergencyMode(isChoiceYes,
mAirplaneModePreference.isChecked());
}
}
@@ -174,4 +198,72 @@ public class AirplaneModePreferenceController extends TogglePreferenceController
mAirplaneModePreference.setChecked(isAirplaneModeOn);
}
}
+
+ /**
+ * According to slice framework, need override this function and provide background
+ * worker class to support slice's dynamic update.
+ */
+ @Override
+ public Class<? extends SliceBackgroundWorker> getBackgroundWorkerClass() {
+ return AirplaneModeSliceWorker.class;
+ }
+
+ /**
+ * Register content observer for URI Settings.Global.AIRPLANE_MODE_ON.
+ * If changed, notify airplane mode slice do rebind.
+ */
+ public static class AirplaneModeSliceWorker extends SliceBackgroundWorker<Void> {
+ private AirplaneModeContentObserver mContentObserver;
+
+ public AirplaneModeSliceWorker(Context context, Uri uri) {
+ super(context, uri);
+ final Handler handler = new Handler(Looper.getMainLooper());
+ mContentObserver = new AirplaneModeContentObserver(handler, this);
+ }
+
+ @Override
+ protected void onSlicePinned() {
+ mContentObserver.register(getContext());
+ }
+
+ @Override
+ protected void onSliceUnpinned() {
+ mContentObserver.unRegister(getContext());
+ }
+
+ @Override
+ public void close() throws IOException {
+ mContentObserver = null;
+ }
+
+ public void updateSlice() {
+ notifySliceChange();
+ }
+
+ public class AirplaneModeContentObserver extends ContentObserver {
+ private final AirplaneModeSliceWorker mSliceBackgroundWorker;
+
+ public AirplaneModeContentObserver(Handler handler,
+ AirplaneModeSliceWorker backgroundWorker) {
+ super(handler);
+ mSliceBackgroundWorker = backgroundWorker;
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mSliceBackgroundWorker.updateSlice();
+ }
+
+ public void register(Context context) {
+ final Uri airplaneModeUri = Settings.Global.getUriFor(
+ Settings.Global.AIRPLANE_MODE_ON);
+ context.getContentResolver().registerContentObserver(airplaneModeUri,
+ false, this);
+ }
+
+ public void unRegister(Context context) {
+ context.getContentResolver().unregisterContentObserver(this);
+ }
+ }
+ }
}
diff --git a/src/com/android/settings/network/MobileNetworkListController.java b/src/com/android/settings/network/MobileNetworkListController.java
index d7fc8b4d58..0d0248eaeb 100644
--- a/src/com/android/settings/network/MobileNetworkListController.java
+++ b/src/com/android/settings/network/MobileNetworkListController.java
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.provider.Settings;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.util.ArrayMap;
import androidx.lifecycle.Lifecycle;
@@ -122,7 +123,10 @@ public class MobileNetworkListController extends AbstractPreferenceController im
pref.setSummary(R.string.mobile_network_inactive_esim);
}
} else {
- if (mSubscriptionManager.isActiveSubscriptionId(subId)) {
+ int slotId = mSubscriptionManager.getPhoneId(subId);
+ if (mSubscriptionManager.isActiveSubscriptionId(subId) &&
+ mSubscriptionManager.getSimStateForSlotIndex(slotId) !=
+ TelephonyManager.SIM_STATE_NOT_READY) {
pref.setSummary(R.string.mobile_network_active_sim);
} else if (SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager)) {
pref.setSummary(mContext.getString(R.string.mobile_network_inactive_sim));
diff --git a/src/com/android/settings/network/MobileNetworkPreferenceController.java b/src/com/android/settings/network/MobileNetworkPreferenceController.java
index 527a632d70..c9d4aa6be8 100644
--- a/src/com/android/settings/network/MobileNetworkPreferenceController.java
+++ b/src/com/android/settings/network/MobileNetworkPreferenceController.java
@@ -21,6 +21,7 @@ import static android.os.UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS;
import static androidx.lifecycle.Lifecycle.Event;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -28,6 +29,8 @@ import android.os.UserManager;
import android.provider.Settings;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
@@ -42,9 +45,11 @@ import com.android.settings.network.telephony.MobileNetworkActivity;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedPreference;
-import com.android.settingslib.Utils;
+import com.android.settings.Utils;
import com.android.settingslib.core.AbstractPreferenceController;
+import java.util.List;
+
public class MobileNetworkPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin, LifecycleObserver {
@@ -57,9 +62,12 @@ public class MobileNetworkPreferenceController extends AbstractPreferenceControl
private Preference mPreference;
@VisibleForTesting
MobileNetworkTelephonyCallback mTelephonyCallback;
+ private SubscriptionManager mSubscriptionManager;
private BroadcastReceiver mAirplanModeChangedReceiver;
+ private String mSummary;
+
public MobileNetworkPreferenceController(Context context) {
super(context);
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -69,9 +77,11 @@ public class MobileNetworkPreferenceController extends AbstractPreferenceControl
mAirplanModeChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
+ updateDisplayName();
updateState(mPreference);
}
};
+ mSubscriptionManager = SubscriptionManager.from(context);
}
@Override
@@ -102,12 +112,15 @@ public class MobileNetworkPreferenceController extends AbstractPreferenceControl
TelephonyCallback.ServiceStateListener {
@Override
public void onServiceStateChanged(ServiceState serviceState) {
+ updateDisplayName();
updateState(mPreference);
}
}
@OnLifecycleEvent(Event.ON_START)
public void onStart() {
+ if (mSubscriptionManager != null)
+ mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
if (isAvailable()) {
if (mTelephonyCallback == null) {
mTelephonyCallback = new MobileNetworkTelephonyCallback();
@@ -121,11 +134,53 @@ public class MobileNetworkPreferenceController extends AbstractPreferenceControl
}
}
+ private void updateDisplayName() {
+ if (mPreference != null) {
+ List<SubscriptionInfo> list = mSubscriptionManager.getActiveSubscriptionInfoList();
+ if (list != null && !list.isEmpty()) {
+ boolean useSeparator = false;
+ StringBuilder builder = new StringBuilder();
+ for (SubscriptionInfo subInfo : list) {
+ if (isSubscriptionInService(subInfo.getSubscriptionId())) {
+ if (useSeparator) builder.append(", ");
+ builder.append(mTelephonyManager.getNetworkOperatorName
+ (subInfo.getSubscriptionId()));
+ useSeparator = true;
+ }
+ }
+ mSummary = builder.toString();
+ } else {
+ mSummary = mTelephonyManager.getNetworkOperatorName();
+ }
+ }
+ }
+
+ private boolean isSubscriptionInService(int subId) {
+ if (mTelephonyManager != null) {
+ if (mTelephonyManager.getServiceStateForSubscriber(subId).getState()
+ == ServiceState.STATE_IN_SERVICE) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private final SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangeListener
+ = new SubscriptionManager.OnSubscriptionsChangedListener() {
+ @Override
+ public void onSubscriptionsChanged() {
+ updateDisplayName();
+ updateState(mPreference);
+ }
+ };
+
@OnLifecycleEvent(Event.ON_STOP)
public void onStop() {
if (mTelephonyCallback != null) {
mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallback);
}
+ mSubscriptionManager
+ .removeOnSubscriptionsChangedListener(mOnSubscriptionsChangeListener);
if (mAirplanModeChangedReceiver != null) {
mContext.unregisterReceiver(mAirplanModeChangedReceiver);
}
@@ -155,6 +210,6 @@ public class MobileNetworkPreferenceController extends AbstractPreferenceControl
@Override
public CharSequence getSummary() {
- return MobileNetworkUtils.getCurrentCarrierNameForDisplay(mContext);
+ return mSummary;
}
}
diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java
index 286e4e36e5..06dd92f3b6 100644
--- a/src/com/android/settings/network/NetworkDashboardFragment.java
+++ b/src/com/android/settings/network/NetworkDashboardFragment.java
@@ -20,6 +20,7 @@ import static com.android.settings.network.MobilePlanPreferenceController.MANAGE
import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.Context;
+import android.content.Intent;
import android.os.Bundle;
import android.provider.SearchIndexableResource;
import android.util.Log;
@@ -31,6 +32,7 @@ import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.network.MobilePlanPreferenceController.MobilePlanPreferenceHost;
+import com.android.settings.network.telephony.TelephonyUtils;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.wifi.WifiPrimarySwitchPreferenceController;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -72,6 +74,12 @@ public class NetworkDashboardFragment extends DashboardFragment implements
}
@Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ use(AirplaneModePreferenceController.class).onActivityResult(requestCode, resultCode, data);
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+ @Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
super.onCreatePreferences(savedInstanceState, rootKey);
use(AllInOneTetherPreferenceController.class).initEnabler(getSettingsLifecycle());
@@ -91,6 +99,8 @@ public class NetworkDashboardFragment extends DashboardFragment implements
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
Lifecycle lifecycle, MetricsFeatureProvider metricsFeatureProvider, Fragment fragment,
MobilePlanPreferenceHost mobilePlanHost) {
+ // Connect to ExtTelephonyService
+ TelephonyUtils.connectExtTelephonyService(context);
final MobilePlanPreferenceController mobilePlanPreferenceController =
new MobilePlanPreferenceController(context, mobilePlanHost);
final InternetPreferenceController internetPreferenceController =
diff --git a/src/com/android/settings/network/ProviderModelSliceHelper.java b/src/com/android/settings/network/ProviderModelSliceHelper.java
index 32a475a7d0..d264fd69d3 100644
--- a/src/com/android/settings/network/ProviderModelSliceHelper.java
+++ b/src/com/android/settings/network/ProviderModelSliceHelper.java
@@ -140,7 +140,7 @@ public class ProviderModelSliceHelper {
numLevels += 1;
}
return MobileNetworkUtils.getSignalStrengthIcon(mContext, level, numLevels,
- NO_CELL_DATA_TYPE_ICON, false);
+ NO_CELL_DATA_TYPE_ICON, !mTelephonyManager.isDataEnabled());
}
/**
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index 2d6077868d..7222b6d2b7 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -368,7 +368,7 @@ public class SubscriptionUtil {
* Whether Settings should show a "Use SIM" toggle in pSIM detailed page.
*/
public static boolean showToggleForPhysicalSim(SubscriptionManager subMgr) {
- return subMgr.canDisablePhysicalSubscription();
+ return true;
}
/**
diff --git a/src/com/android/settings/network/SubscriptionsChangeListener.java b/src/com/android/settings/network/SubscriptionsChangeListener.java
index e13f85c5ab..2ee22af638 100644
--- a/src/com/android/settings/network/SubscriptionsChangeListener.java
+++ b/src/com/android/settings/network/SubscriptionsChangeListener.java
@@ -72,6 +72,7 @@ public class SubscriptionsChangeListener extends ContentObserver {
}
public void start() {
+ Log.d(TAG, "Start");
mSubscriptionManager.addOnSubscriptionsChangedListener(
mContext.getMainExecutor(), mSubscriptionsChangedListener);
mContext.getContentResolver()
diff --git a/src/com/android/settings/network/TetherPreferenceController.java b/src/com/android/settings/network/TetherPreferenceController.java
index f91f78713d..9544d9a281 100644
--- a/src/com/android/settings/network/TetherPreferenceController.java
+++ b/src/com/android/settings/network/TetherPreferenceController.java
@@ -71,7 +71,11 @@ public class TetherPreferenceController extends AbstractPreferenceController imp
}
public void onServiceDisconnected(int profile) {
- mBluetoothPan.set(null);
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ BluetoothProfile currentProfile = mBluetoothPan.getAndSet(null);
+ if (currentProfile != null && adapter != null) {
+ adapter.closeProfileProxy(BluetoothProfile.PAN, currentProfile);
+ }
}
};
@@ -127,15 +131,20 @@ public class TetherPreferenceController extends AbstractPreferenceController imp
@Override
public void onCreate(Bundle savedInstanceState) {
- if (mBluetoothAdapter != null &&
- mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
- mBluetoothAdapter.getProfileProxy(mContext, mBtProfileServiceListener,
- BluetoothProfile.PAN);
- }
}
@Override
public void onResume() {
+ if (mBluetoothAdapter != null &&
+ mBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
+ final BluetoothProfile profile = mBluetoothPan.get();
+
+ if (profile == null) {
+ mBluetoothAdapter.getProfileProxy(mContext, mBtProfileServiceListener,
+ BluetoothProfile.PAN);
+ }
+ }
+
if (mAirplaneModeObserver == null) {
mAirplaneModeObserver = new SettingObserver();
}
@@ -150,6 +159,10 @@ public class TetherPreferenceController extends AbstractPreferenceController imp
@Override
public void onPause() {
+ final BluetoothProfile profile = mBluetoothPan.getAndSet(null);
+ if (profile != null && mBluetoothAdapter != null) {
+ mBluetoothAdapter.closeProfileProxy(BluetoothProfile.PAN, profile);
+ }
if (mAirplaneModeObserver != null) {
mContext.getContentResolver().unregisterContentObserver(mAirplaneModeObserver);
}
@@ -160,10 +173,6 @@ public class TetherPreferenceController extends AbstractPreferenceController imp
@Override
public void onDestroy() {
- final BluetoothProfile profile = mBluetoothPan.getAndSet(null);
- if (profile != null && mBluetoothAdapter != null) {
- mBluetoothAdapter.closeProfileProxy(BluetoothProfile.PAN, profile);
- }
}
public static boolean isTetherConfigDisallowed(Context context) {
diff --git a/src/com/android/settings/network/UiccSlotUtil.java b/src/com/android/settings/network/UiccSlotUtil.java
index 6113f5a6ae..f05e28911d 100644
--- a/src/com/android/settings/network/UiccSlotUtil.java
+++ b/src/com/android/settings/network/UiccSlotUtil.java
@@ -29,6 +29,7 @@ import com.google.common.collect.ImmutableList;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -69,6 +70,9 @@ public class UiccSlotUtil {
if (slotInfos == null) {
return ImmutableList.of();
}
+ slotInfos = Arrays.stream(slotInfos)
+ .filter(s -> (s != null))
+ .toArray(UiccSlotInfo[]::new);
return ImmutableList.copyOf(slotInfos);
}
@@ -92,22 +96,24 @@ public class UiccSlotUtil {
Log.i(TAG, "Multiple active slots supported. Not calling switchSlots.");
return;
}
- UiccSlotInfo[] slots = telMgr.getUiccSlotsInfo();
+ ImmutableList<UiccSlotInfo> slots = getSlotInfos(telMgr);
+ int length = slots.size();
if (slotId == INVALID_PHYSICAL_SLOT_ID) {
- for (int i = 0; i < slots.length; i++) {
- if (slots[i].isRemovable()
- && !slots[i].getIsActive()
- && slots[i].getCardStateInfo() != UiccSlotInfo.CARD_STATE_INFO_ERROR
- && slots[i].getCardStateInfo() != UiccSlotInfo.CARD_STATE_INFO_RESTRICTED) {
+ for (int i = 0; i < length; i++) {
+ UiccSlotInfo slotInfo = slots.get(i);
+ if (slotInfo.isRemovable()
+ && !slotInfo.getIsActive()
+ && slotInfo.getCardStateInfo() != UiccSlotInfo.CARD_STATE_INFO_ERROR
+ && slotInfo.getCardStateInfo() != UiccSlotInfo.CARD_STATE_INFO_RESTRICTED) {
performSwitchToRemovableSlot(i, context);
return;
}
}
} else {
- if (slotId >= slots.length || !slots[slotId].isRemovable()) {
+ if (slotId >= length || !slots.get(slotId).isRemovable()) {
throw new UiccSlotsException("The given slotId is not a removable slot: " + slotId);
}
- if (!slots[slotId].getIsActive()) {
+ if (!slots.get(slotId).getIsActive()) {
performSwitchToRemovableSlot(slotId, context);
}
}
diff --git a/src/com/android/settings/network/apn/ApnEditor.java b/src/com/android/settings/network/apn/ApnEditor.java
index 03db1b89be..5b9714a8d9 100644
--- a/src/com/android/settings/network/apn/ApnEditor.java
+++ b/src/com/android/settings/network/apn/ApnEditor.java
@@ -55,6 +55,7 @@ import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.network.ProxySubscriptionManager;
import com.android.settingslib.utils.ThreadUtils;
+import com.android.settings.Utils;
import java.util.Arrays;
import java.util.HashSet;
@@ -150,6 +151,8 @@ public class ApnEditor extends SettingsPreferenceFragment
private boolean mReadOnlyApn;
private Uri mCarrierUri;
+ private static final String APN_DEFALUT_VALUES_STRING_ARRAY = "apn_default_values_strings_array";
+
/**
* APN types for data connections. These are usage categories for an APN
* entry. One APN entry may support multiple APN types, eg, a single APN
@@ -230,6 +233,26 @@ public class ApnEditor extends SettingsPreferenceFragment
Telephony.Carriers.USER_EDITABLE //24
};
+ private static final String[] sUIConfigurableItems = new String[] {
+ Telephony.Carriers.NAME,
+ Telephony.Carriers.APN,
+ Telephony.Carriers.PROXY,
+ Telephony.Carriers.PORT,
+ Telephony.Carriers.USER,
+ Telephony.Carriers.SERVER,
+ Telephony.Carriers.PASSWORD,
+ Telephony.Carriers.MMSC,
+ Telephony.Carriers.MMSPROXY,
+ Telephony.Carriers.MMSPORT,
+ Telephony.Carriers.AUTH_TYPE,
+ Telephony.Carriers.TYPE,
+ Telephony.Carriers.PROTOCOL,
+ Telephony.Carriers.CARRIER_ENABLED,
+ Telephony.Carriers.BEARER,
+ Telephony.Carriers.BEARER_BITMASK,
+ Telephony.Carriers.ROAMING_PROTOCOL,
+ };
+
private static final int ID_INDEX = 0;
@VisibleForTesting
static final int NAME_INDEX = 1;
@@ -311,6 +334,9 @@ public class ApnEditor extends SettingsPreferenceFragment
mApnData = getApnDataFromUri(uri);
} else {
mApnData = new ApnData(sProjection.length);
+ if (action.equals(Intent.ACTION_INSERT)) {
+ setDefaultData();
+ }
}
final boolean isUserEdited = mApnData.getInteger(EDITED_INDEX,
@@ -598,6 +624,10 @@ public class ApnEditor extends SettingsPreferenceFragment
mMvnoType.setValue(mMvnoTypeStr);
mMvnoMatchData.setText(mMvnoMatchDataStr);
}
+ String localizedName = Utils.getLocalizedName(getActivity(), mApnData.getString(NAME_INDEX));
+ if (!TextUtils.isEmpty(localizedName)) {
+ mName.setText(localizedName);
+ }
}
mName.setSummary(checkNull(mName.getText()));
@@ -728,6 +758,11 @@ public class ApnEditor extends SettingsPreferenceFragment
telephonyManager = telephonyManagerForSubId;
}
mMvnoMatchData.setText(telephonyManager.getGroupIdLevel1());
+ } else if (values[mvnoIndex].equals("ICCID")) {
+ if (mMvnoMatchDataStr != null) {
+ Log.d(TAG, "mMvnoMatchDataStr: " + mMvnoMatchDataStr);
+ mMvnoMatchData.setText(mMvnoMatchDataStr);
+ }
} else {
// mvno type 'none' case. At this time, mvnoIndex should be 0.
mMvnoMatchData.setText("");
@@ -1232,6 +1267,51 @@ public class ApnEditor extends SettingsPreferenceFragment
return sNotSet.equals(value) ? null : value;
}
+ private void setDefaultData() {
+ CarrierConfigManager configManager = (CarrierConfigManager)
+ getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ if (configManager != null) {
+ PersistableBundle b = configManager.getConfigForSubId(mSubId);
+ if (b != null) {
+ PersistableBundle defaultValues = b.getPersistableBundle(
+ APN_DEFALUT_VALUES_STRING_ARRAY);
+ if (defaultValues != null && !defaultValues.isEmpty()) {
+ Set<String> keys = defaultValues.keySet();
+ for (String key : keys) {
+ if (fieldValidate(key)) {
+ setAppData(key, defaultValues.get(key));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void setAppData(String key, Object object) {
+ int index = findIndexOfKey(key);
+ if (index >= 0) {
+ mApnData.setObject(index, object);
+ }
+ }
+
+ private int findIndexOfKey(String key) {
+ for(int i = 0; i < sProjection.length; i++) {
+ if (sProjection[i].equals(key)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ private boolean fieldValidate(String field){
+ for(String tableField : sUIConfigurableItems){
+ if(tableField.equalsIgnoreCase(field))
+ return true;
+ }
+ Log.w(TAG, field + " is not configurable");
+ return false;
+ }
+
@VisibleForTesting
String getUserEnteredApnType() {
// if user has not specified a type, map it to "ALL APN TYPES THAT ARE NOT READ-ONLY"
@@ -1467,6 +1547,10 @@ public class ApnEditor extends SettingsPreferenceFragment
String getString(int index) {
return (String) mData[index];
}
+
+ void setObject(int index, Object value) {
+ mData[index] = value;
+ }
}
private static int getBitmaskForTech(int radioTech) {
diff --git a/src/com/android/settings/network/apn/ApnPreference.java b/src/com/android/settings/network/apn/ApnPreference.java
index f277db0abd..b9ae6bf3c5 100755
--- a/src/com/android/settings/network/apn/ApnPreference.java
+++ b/src/com/android/settings/network/apn/ApnPreference.java
@@ -114,6 +114,13 @@ public class ApnPreference extends Preference implements CompoundButton.OnChecke
sSelectedKey = getKey();
}
+
+ // ApnPreference.sSelectedKey static variable is shared for MSim case,
+ // need be initialized according to preferred apn id per sub
+ public static void setSelectedKey(String preferredApnKey) {
+ sSelectedKey = preferredApnKey;
+ }
+
/**
* Change the preference status.
*/
diff --git a/src/com/android/settings/network/apn/ApnSettings.java b/src/com/android/settings/network/apn/ApnSettings.java
index 4df2e5ee38..21b752bd16 100755
--- a/src/com/android/settings/network/apn/ApnSettings.java
+++ b/src/com/android/settings/network/apn/ApnSettings.java
@@ -26,6 +26,7 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources.NotFoundException;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
@@ -40,6 +41,7 @@ import android.provider.Telephony;
import android.telephony.CarrierConfigManager;
import android.telephony.PhoneStateListener;
import android.telephony.PreciseDataConnectionState;
+import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -54,13 +56,19 @@ import android.widget.Toast;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
+import com.android.ims.ImsManager;
import com.android.settings.R;
import com.android.settings.RestrictedSettingsFragment;
import com.android.settings.network.SubscriptionUtil;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import com.android.settings.Utils;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
/** Handle each different apn setting. */
public class ApnSettings extends RestrictedSettingsFragment
@@ -86,6 +94,8 @@ public class ApnSettings extends RestrictedSettingsFragment
Telephony.Carriers.MVNO_TYPE,
Telephony.Carriers.MVNO_MATCH_DATA,
Telephony.Carriers.EDITED_STATUS,
+ Telephony.Carriers.BEARER,
+ Telephony.Carriers.BEARER_BITMASK,
};
/** Copied from {@code com.android.internal.telephony.TelephonyIntents} */
@@ -102,6 +112,8 @@ public class ApnSettings extends RestrictedSettingsFragment
private static final int MVNO_TYPE_INDEX = 4;
private static final int MVNO_MATCH_DATA_INDEX = 5;
private static final int EDITED_INDEX = 6;
+ private static final int BEARER_INDEX = 7;
+ private static final int BEARER_BITMASK_INDEX = 8;
private static final int MENU_NEW = Menu.FIRST;
private static final int MENU_RESTORE = Menu.FIRST + 1;
@@ -137,6 +149,16 @@ public class ApnSettings extends RestrictedSettingsFragment
private boolean mAllowAddingApns;
private boolean mHidePresetApnDetails;
+ private String[] mHideApnsWithRule;
+ private String[] mHideApnsWithIccidRule;
+ private PersistableBundle mHideApnsGroupByIccid;
+ private final static String INCLUDE_COMMON_RULES = "include_common_rules";
+ private final static String APN_HIDE_RULE_STRINGS_ARRAY= "apn_hide_rule_strings_array";
+ private final static String APN_HIDE_RULE_STRINGS_WITH_ICCIDS_ARRAY = "apn_hide_rule_strings_with_iccids_array";
+
+ private final static String ACTION_VOLTE_ENABLED_STATE_CHANGED
+ = "org.codeaurora.intent.action.ACTION_ENHANCE_4G_SWITCH";
+
public ApnSettings() {
super(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
}
@@ -183,6 +205,12 @@ public class ApnSettings extends RestrictedSettingsFragment
restartPhoneStateListener(mSubId);
}
fillList();
+ } else if (intent.getAction().equals(ACTION_VOLTE_ENABLED_STATE_CHANGED)) {
+ if (!mRestoreDefaultApnMode) {
+ fillList();
+ } else {
+ showDialog(DIALOG_RESTORE_DEFAULTAPN);
+ }
}
}
};
@@ -220,6 +248,9 @@ public class ApnSettings extends RestrictedSettingsFragment
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED);
mIntentFilter.addAction(ACTION_SIM_STATE_CHANGED);
+ if (Utils.isSupportCTPA(getActivity().getApplicationContext())) {
+ mIntentFilter.addAction(ACTION_VOLTE_ENABLED_STATE_CHANGED);
+ }
setIfOnlyAvailableForAdmins(true);
@@ -231,6 +262,14 @@ public class ApnSettings extends RestrictedSettingsFragment
final PersistableBundle b = configManager.getConfigForSubId(mSubId);
mHideImsApn = b.getBoolean(CarrierConfigManager.KEY_HIDE_IMS_APN_BOOL);
mAllowAddingApns = b.getBoolean(CarrierConfigManager.KEY_ALLOW_ADDING_APNS_BOOL);
+
+ mHideApnsWithRule = b.getStringArray(APN_HIDE_RULE_STRINGS_ARRAY);
+ mHideApnsWithIccidRule = b.getStringArray(APN_HIDE_RULE_STRINGS_WITH_ICCIDS_ARRAY);
+ if(mSubscriptionInfo != null){
+ String iccid = mSubscriptionInfo.getIccId();
+ Log.d(TAG, "iccid: " + iccid);
+ mHideApnsGroupByIccid = b.getPersistableBundle(iccid);
+ }
if (mAllowAddingApns) {
final String[] readOnlyApnTypes = b.getStringArray(
CarrierConfigManager.KEY_READ_ONLY_APN_TYPES_STRING_ARRAY);
@@ -323,10 +362,18 @@ public class ApnSettings extends RestrictedSettingsFragment
new StringBuilder("NOT (type='ia' AND (apn=\"\" OR apn IS NULL)) AND "
+ "user_visible!=0");
- if (mHideImsApn) {
+ int phoneId = SubscriptionManager.getPhoneId(subId);
+ Context appContext = getActivity().getApplicationContext();
+ boolean isVoLTEEnabled = ImsManager.getInstance(appContext, phoneId)
+ .isEnhanced4gLteModeSettingEnabledByUser();
+ if (mHideImsApn || (Utils.isSupportCTPA(appContext) && !isVoLTEEnabled)) {
where.append(" AND NOT (type='ims')");
}
+ appendFilter(where);
+
+ Log.d(TAG, "where = " + where.toString());
+
final Cursor cursor = getContentResolver().query(simApnUri,
CARRIERS_PROJECTION, where.toString(), null,
Telephony.Carriers.DEFAULT_SORT_ORDER);
@@ -339,9 +386,13 @@ public class ApnSettings extends RestrictedSettingsFragment
final ArrayList<ApnPreference> mmsApnList = new ArrayList<ApnPreference>();
mSelectedKey = getSelectedApnKey();
+
+ // ApnPreference.mSelectedKey static variable is shared for MSim case,
+ // need be initialized according to preferred apn id per sub
+ ApnPreference.setSelectedKey(mSelectedKey);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
- final String name = cursor.getString(NAME_INDEX);
+ String name = cursor.getString(NAME_INDEX);
final String apn = cursor.getString(APN_INDEX);
final String key = cursor.getString(ID_INDEX);
final String type = cursor.getString(TYPES_INDEX);
@@ -349,6 +400,26 @@ public class ApnSettings extends RestrictedSettingsFragment
mMvnoType = cursor.getString(MVNO_TYPE_INDEX);
mMvnoMatchData = cursor.getString(MVNO_MATCH_DATA_INDEX);
+ //Special requirement of some operators, need change APN name follow language.
+ String localizedName = Utils.getLocalizedName(getActivity(), cursor.getString(NAME_INDEX));
+
+ if (!TextUtils.isEmpty(localizedName)) {
+ name = localizedName;
+ }
+ int bearer = cursor.getInt(BEARER_INDEX);
+ int bearerBitMask = cursor.getInt(BEARER_BITMASK_INDEX);
+ int fullBearer = ServiceState.getBitmaskForTech(bearer) | bearerBitMask;
+ int radioTech = networkTypeToRilRidioTechnology(TelephonyManager.getDefault()
+ .getDataNetworkType(subId));
+ if (!ServiceState.bitmaskHasTech(fullBearer, radioTech)
+ && (bearer != 0 || bearerBitMask != 0)) {
+ // In OOS, show APN with bearer as default
+ if ((radioTech != ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) || (bearer == 0
+ && radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN)) {
+ cursor.moveToNext();
+ continue;
+ }
+ }
final ApnPreference pref = new ApnPreference(getPrefContext());
pref.setKey(key);
@@ -362,8 +433,11 @@ public class ApnSettings extends RestrictedSettingsFragment
pref.setSummary(apn);
}
- final boolean selectable =
+ boolean selectable =
((type == null) || type.contains(ApnSetting.TYPE_DEFAULT_STRING));
+ if (isVoLTEEnabled && selectable && Utils.isSupportCTPA(appContext)) {
+ selectable = ((type == null) || !type.equals("ims"));
+ }
pref.setSelectable(selectable);
if (selectable) {
if ((mSelectedKey != null) && mSelectedKey.equals(key)) {
@@ -386,6 +460,152 @@ public class ApnSettings extends RestrictedSettingsFragment
}
}
+ private void appendFilter(StringBuilder where){
+ boolean includeCommon = true;
+ if(mHideApnsGroupByIccid != null && !mHideApnsGroupByIccid.isEmpty()){
+ // APN hidden rules according to the specified iccid,
+ // it should be configured in CarrierConfig as below.
+ // <map name="12345">
+ // <string name="type">fota</string>
+ // <boolean name="include_common_rules" value="true"/>
+ // </map>
+ includeCommon = mHideApnsGroupByIccid.getBoolean(INCLUDE_COMMON_RULES, true);
+ Log.d(TAG, "apn hidden rules specified iccid, include common rule: " + includeCommon);
+ Set<String> keys = mHideApnsGroupByIccid.keySet();
+ for(String key : keys){
+ if(Utils.carrierTableFieldValidate(key)){
+ String value = mHideApnsGroupByIccid.getString(key);
+ if(value != null){
+ where.append(" AND " + key + " <> \"" + value + "\"");
+ }
+ }
+ }
+ }
+
+ // Some operator have special APN hidden rules group by iccids,
+ // it should be configured in CarrierConfig as below,
+ // it maybe overwrite some rules defined in common rules.
+ // <string-array name="apn_hide_rule_strings_with_iccids_array" num="6">
+ // <item value="iccid"/>
+ // <item value="1111,2222"/>
+ // <item value="type"/>
+ // <item value="ims,emergency"/>
+ // <item value="include_common_rules"/>
+ // <item value="true"/>
+ // </string-array>
+ if(mHideApnsWithIccidRule != null){
+ HashMap<String, String> ruleWithIccid = getApnRuleMap(mHideApnsWithIccidRule);
+ final String iccid = mSubscriptionInfo == null ? "" : mSubscriptionInfo.getIccId();
+ if(isOperatorIccid(ruleWithIccid, iccid)){
+ String s = ruleWithIccid.get(INCLUDE_COMMON_RULES);
+ includeCommon = !(s != null && s.equalsIgnoreCase(String.valueOf(false)));
+ Log.d(TAG, "apn hidden rules in iccids, include common rule: " + includeCommon);
+ filterWithKey(ruleWithIccid, where);
+ }
+ }
+
+ if(includeCommon){
+ // Common APN hidden rules,
+ // it should be configured in CarrierConfig as below.
+ // <string-array name="apn_default_values_strings_array" num="2">
+ // <item value="type"/>
+ // <item value="fota"/>
+ // </string-array>
+ if(mHideApnsWithRule != null){
+ HashMap<String, String> rule = getApnRuleMap(mHideApnsWithRule);
+ filterWithKey(rule, where);
+ }
+ }
+ }
+
+ private void filterWithKey(Map<String, String> rules, StringBuilder where) {
+ Set<String> fields = rules.keySet();
+ for(String field : fields){
+ if(Utils.carrierTableFieldValidate(field)){
+ String value = rules.get(field);
+ if(!TextUtils.isEmpty(value)){
+ String[] subValues = value.split(",");
+ for(String subValue : subValues){
+ where.append(" AND " + field + " <> \"" + subValue + "\"");
+ }
+ }
+ }
+ }
+ }
+
+ private HashMap<String, String> getApnRuleMap(String[] ruleArray) {
+ HashMap<String, String> rules = new HashMap<String, String>();
+ if (ruleArray != null) {
+ int length = ruleArray.length;
+ Log.d(TAG, "ruleArray size = " + length);
+ if (length > 0 && (length % 2 == 0)) {
+ for (int i = 0; i < length;) {
+ rules.put(ruleArray[i].toLowerCase(), ruleArray[i + 1]);
+ i += 2;
+ }
+ }
+ }
+ return rules;
+ }
+
+ private boolean isOperatorIccid(HashMap<String, String> ruleMap, String iccid) {
+ String valuesOfIccid = ruleMap.get("iccid");
+ if (!TextUtils.isEmpty(valuesOfIccid)) {
+ String[] iccids = valuesOfIccid.split(",");
+ for (String subIccid : iccids) {
+ if (iccid.startsWith(subIccid.trim())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private int networkTypeToRilRidioTechnology(int nt) {
+ switch(nt) {
+ case TelephonyManager.NETWORK_TYPE_GPRS:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_GPRS;
+ case TelephonyManager.NETWORK_TYPE_EDGE:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_EDGE;
+ case TelephonyManager.NETWORK_TYPE_UMTS:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_UMTS;
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA;
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA;
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_HSPA;
+ case TelephonyManager.NETWORK_TYPE_CDMA:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_IS95B;
+ case TelephonyManager.NETWORK_TYPE_1xRTT:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT;
+ case TelephonyManager.NETWORK_TYPE_EVDO_0:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0;
+ case TelephonyManager.NETWORK_TYPE_EVDO_A:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A;
+ case TelephonyManager.NETWORK_TYPE_EVDO_B:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B;
+ case TelephonyManager.NETWORK_TYPE_EHRPD:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD;
+ case TelephonyManager.NETWORK_TYPE_LTE:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_LTE;
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP;
+ case TelephonyManager.NETWORK_TYPE_GSM:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_GSM;
+ case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA;
+ case TelephonyManager.NETWORK_TYPE_IWLAN:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
+ case TelephonyManager.NETWORK_TYPE_LTE_CA:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_LTE_CA;
+ case TelephonyManager.NETWORK_TYPE_NR:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_NR;
+ default:
+ return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
+ }
+ }
+
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if (!mUnavailable) {
diff --git a/src/com/android/settings/network/telephony/BackupCallingPreferenceController.java b/src/com/android/settings/network/telephony/BackupCallingPreferenceController.java
index 4f64399f52..656019a4b7 100644
--- a/src/com/android/settings/network/telephony/BackupCallingPreferenceController.java
+++ b/src/com/android/settings/network/telephony/BackupCallingPreferenceController.java
@@ -18,6 +18,7 @@ package com.android.settings.network.telephony;
import android.content.Context;
import android.os.PersistableBundle;
+import android.os.RemoteException;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -33,6 +34,9 @@ import com.android.settings.R;
import com.android.settings.network.SubscriptionUtil;
import com.android.settings.network.ims.WifiCallingQueryImsState;
+import com.qti.extphone.ExtTelephonyManager;
+import com.qti.extphone.ServiceCallback;
+
import java.util.List;
import java.util.Objects;
@@ -44,6 +48,9 @@ public class BackupCallingPreferenceController extends TelephonyTogglePreference
private static final String LOG_TAG = "BackupCallingPrefCtrl";
private Preference mPreference;
+ private Context mContext;
+ private ExtTelephonyManager mExtTelephonyManager;
+ private boolean mServiceConnected = false;
/**
* Class constructor of backup calling.
@@ -53,8 +60,29 @@ public class BackupCallingPreferenceController extends TelephonyTogglePreference
**/
public BackupCallingPreferenceController(Context context, String key) {
super(context, key);
+ mContext = context.getApplicationContext();
+ mExtTelephonyManager = ExtTelephonyManager.getInstance(mContext);
+ mExtTelephonyManager.connectService(mExtTelManagerServiceCallback);
}
+ private ServiceCallback mExtTelManagerServiceCallback = new ServiceCallback() {
+
+ // Since ExtTelephony service is called from TelephonyComponentFactory,
+ // onConnected() is called even before mExtTelephonyManager.connectService
+ // as per ExtTelephonyManager#connectService()
+ @Override
+ public void onConnected() {
+ Log.d(LOG_TAG, "mExtTelManagerServiceCallback: service connected");
+ mServiceConnected = true;
+ }
+
+ @Override
+ public void onDisconnected() {
+ Log.d(LOG_TAG, "mExtTelManagerServiceCallback: service disconnected");
+ mServiceConnected = false;
+ }
+ };
+
/**
* Initialization based on given subscription id.
*
@@ -76,7 +104,7 @@ public class BackupCallingPreferenceController extends TelephonyTogglePreference
if (subInfo == null) { // given subId is not actives
return CONDITIONALLY_UNAVAILABLE;
}
- return (subIdList.size() > 1) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ return (subIdList.size() == 1) ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
/**
@@ -152,6 +180,22 @@ public class BackupCallingPreferenceController extends TelephonyTogglePreference
}
protected boolean isCrossSimEnabledByPlatform(Context context, int subscriptionId) {
+ if (!mServiceConnected) {
+ Log.d(LOG_TAG, "ExtTelephony service is not connected");
+ return false;
+ }
+
+ try {
+ if (!mExtTelephonyManager.isEpdgOverCellularDataSupported(
+ SubscriptionManager.getPhoneId(subscriptionId))) {
+ Log.d(LOG_TAG, "Not supported by platform. subId = " + subscriptionId);
+ return false;
+ }
+ } catch(RemoteException ex) {
+ Log.d(LOG_TAG, "isEpdgOverCellularDataSupported Exception" + ex);
+ return false;
+ }
+
// TODO : Change into API which created for accessing
// com.android.ims.ImsManager#isCrossSimEnabledByPlatform()
if ((new WifiCallingQueryImsState(context, subscriptionId)).isWifiCallingSupported()) {
diff --git a/src/com/android/settings/network/telephony/CellInfoUtil.java b/src/com/android/settings/network/telephony/CellInfoUtil.java
index 58b668b7d0..0d9dd3f0ae 100644
--- a/src/com/android/settings/network/telephony/CellInfoUtil.java
+++ b/src/com/android/settings/network/telephony/CellInfoUtil.java
@@ -16,6 +16,7 @@
package com.android.settings.network.telephony;
+import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.CellIdentity;
import android.telephony.CellIdentityGsm;
import android.telephony.CellIdentityLte;
@@ -29,6 +30,7 @@ import android.telephony.CellInfoLte;
import android.telephony.CellInfoNr;
import android.telephony.CellInfoTdscdma;
import android.telephony.CellInfoWcdma;
+import android.telephony.ServiceState;
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
@@ -132,6 +134,139 @@ public final class CellInfoUtil {
return ci;
}
+ /**
+ * Creates a CellInfo object from OperatorInfo for Legacy Incremental Scan results.
+ */
+ public static CellInfo convertLegacyIncrScanOperatorInfoToCellInfo(OperatorInfo operatorInfo) {
+ final String operatorNumeric = operatorInfo.getOperatorNumeric();
+ String mcc = null;
+ String mnc = null;
+ String ran = String.valueOf(AccessNetworkType.UNKNOWN);
+
+ if (operatorNumeric != null) {
+ if (operatorNumeric.matches("^[0-9]{5,6}$")) {
+ mcc = operatorNumeric.substring(0, 3);
+ mnc = operatorNumeric.substring(3);
+ } else if (operatorNumeric.matches("^[0-9]{5,6}[+][0-9]{1,2}$")) {
+ // If the operator numeric contains the RAN, then parse the MCC-MNC accordingly
+ String values[] = operatorNumeric.split("\\+");
+ mcc = values[0].substring(0, 3);
+ mnc = values[0].substring(3);
+ ran = values[1];
+ }
+ }
+
+ CellInfoNr cellInfoNr = null;
+ CellInfoLte cellInfoLte = null;
+ CellInfoWcdma cellInfoWcdma = null;
+ CellInfoGsm cellInfoGsm = null;
+ CellInfoGsm cellInfoDefault = null;
+
+ // Convert RadioAccessNetwork(ran) to AccessNetworkType
+ int accessNetworkType = AccessNetworkType.convertRanToAnt(Integer.parseInt(ran));
+
+ switch(accessNetworkType) {
+ case AccessNetworkType.NGRAN:
+ // 5G
+ CellIdentityNr cellIdentityNr = new CellIdentityNr(
+ Integer.MAX_VALUE /* pci */,
+ Integer.MAX_VALUE /* tac */,
+ Integer.MAX_VALUE /* nrArfcn */,
+ null /* bands */,
+ mcc,
+ mnc,
+ Integer.MAX_VALUE /* nci */,
+ operatorInfo.getOperatorAlphaLong() + " 5G",
+ operatorInfo.getOperatorAlphaShort() + " 5G",
+ Collections.emptyList());
+ cellInfoNr = new CellInfoNr();
+ cellInfoNr.setCellIdentity(cellIdentityNr);
+ break;
+
+ case AccessNetworkType.EUTRAN:
+ // 4G
+ CellIdentityLte cellIdentityLte = new CellIdentityLte(
+ Integer.MAX_VALUE /* ci */,
+ Integer.MAX_VALUE /* pci */,
+ Integer.MAX_VALUE /* tac */,
+ Integer.MAX_VALUE /* earfcn */,
+ null /* bands */,
+ Integer.MAX_VALUE /* bandwidth */,
+ mcc,
+ mnc,
+ operatorInfo.getOperatorAlphaLong() + " 4G",
+ operatorInfo.getOperatorAlphaShort() + " 4G",
+ Collections.emptyList(),
+ null /* csgInfo */);
+ cellInfoLte = new CellInfoLte();
+ cellInfoLte.setCellIdentity(cellIdentityLte);
+ break;
+
+ case AccessNetworkType.UTRAN:
+ CellIdentityWcdma cellIdentityWcdma = new CellIdentityWcdma(
+ Integer.MAX_VALUE /* lac */,
+ Integer.MAX_VALUE /* cid */,
+ Integer.MAX_VALUE /* psc */,
+ Integer.MAX_VALUE /* uarfcn */,
+ mcc,
+ mnc,
+ operatorInfo.getOperatorAlphaLong() + " 3G",
+ operatorInfo.getOperatorAlphaShort() + " 3G",
+ Collections.emptyList(),
+ null /* csgInfo */);
+ cellInfoWcdma = new CellInfoWcdma();
+ cellInfoWcdma.setCellIdentity(cellIdentityWcdma);
+ break;
+
+ case AccessNetworkType.GERAN:
+ // 2G
+ CellIdentityGsm cellIdentityGsm = new CellIdentityGsm(
+ Integer.MAX_VALUE /* lac */,
+ Integer.MAX_VALUE /* cid */,
+ Integer.MAX_VALUE /* arfcn */,
+ Integer.MAX_VALUE /* bsic */,
+ mcc,
+ mnc,
+ operatorInfo.getOperatorAlphaLong() + " 2G",
+ operatorInfo.getOperatorAlphaShort() + " 2G",
+ Collections.emptyList());
+ cellInfoGsm = new CellInfoGsm();
+ cellInfoGsm.setCellIdentity(cellIdentityGsm);
+ break;
+
+ default:
+ // This is when RAT info is not present with the PLMN.
+ // Do not add any network class to the operator name.
+ CellIdentityGsm cellIdentityDefault = new CellIdentityGsm(
+ Integer.MAX_VALUE /* lac */,
+ Integer.MAX_VALUE /* cid */,
+ Integer.MAX_VALUE /* arfcn */,
+ Integer.MAX_VALUE /* bsic */,
+ mcc,
+ mnc,
+ operatorInfo.getOperatorAlphaLong(),
+ operatorInfo.getOperatorAlphaShort(),
+ Collections.emptyList());
+ cellInfoDefault = new CellInfoGsm();
+ cellInfoDefault.setCellIdentity(cellIdentityDefault);
+ break;
+ }
+
+ CellInfo cellInfo = null;
+ if (cellInfoNr != null) cellInfo = cellInfoNr;
+ else if (cellInfoLte != null) cellInfo = cellInfoLte;
+ else if (cellInfoWcdma != null) cellInfo = cellInfoWcdma;
+ else if (cellInfoGsm != null) cellInfo = cellInfoGsm;
+ else cellInfo = cellInfoDefault;
+
+ if (operatorInfo.getState() == OperatorInfo.State.CURRENT) {
+ // Unlike the legacy full scan, legacy incremental scanning using qcril hooks
+ // sends the results containing the info about the currently registered operator.
+ cellInfo.setRegistered(true);
+ }
+ return cellInfo;
+ }
+
/** Convert a list of cellInfos to readable string without sensitive info. */
public static String cellInfoListToString(List<CellInfo> cellInfos) {
return cellInfos.stream()
diff --git a/src/com/android/settings/network/telephony/DataDefaultSubscriptionController.java b/src/com/android/settings/network/telephony/DataDefaultSubscriptionController.java
new file mode 100644
index 0000000000..f4dfbc6769
--- /dev/null
+++ b/src/com/android/settings/network/telephony/DataDefaultSubscriptionController.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved
+ * Not a contribution
+ *
+ * Copyright (C) 2019 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.network.telephony;
+
+ import android.content.Context;
+ import android.telephony.SubscriptionInfo;
+ import android.telephony.SubscriptionManager;
+
+public class DataDefaultSubscriptionController extends DefaultSubscriptionController {
+
+ private static final String SETTING_USER_PREF_DATA_SUB = "user_preferred_data_sub";
+
+ public DataDefaultSubscriptionController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ protected SubscriptionInfo getDefaultSubscriptionInfo() {
+ return mManager.getActiveSubscriptionInfo(getDefaultSubscriptionId());
+ }
+
+ @Override
+ protected int getDefaultSubscriptionId() {
+ return SubscriptionManager.getDefaultDataSubscriptionId();
+ }
+
+ @Override
+ protected void setDefaultSubscription(int subscriptionId) {
+ mManager.setDefaultDataSubId(subscriptionId);
+ setUserPrefDataSubIdInDb(subscriptionId);
+ }
+
+ private void setUserPrefDataSubIdInDb(int subId) {
+ android.provider.Settings.Global.putInt(mContext.getContentResolver(),
+ SETTING_USER_PREF_DATA_SUB, subId);
+ }
+}
diff --git a/src/com/android/settings/network/telephony/DataDuringCallsPreferenceController.java b/src/com/android/settings/network/telephony/DataDuringCallsPreferenceController.java
index 110c5823de..9f95b9e6a9 100644
--- a/src/com/android/settings/network/telephony/DataDuringCallsPreferenceController.java
+++ b/src/com/android/settings/network/telephony/DataDuringCallsPreferenceController.java
@@ -69,6 +69,10 @@ public class DataDuringCallsPreferenceController extends TelephonyTogglePreferen
mMobileDataContentObserver.setOnMobileDataChangedListener(() -> refreshPreference());
}
mMobileDataContentObserver.register(mContext, mSubId);
+ final int defaultDataSub = SubscriptionManager.getDefaultDataSubscriptionId();
+ if (defaultDataSub != mSubId) {
+ mMobileDataContentObserver.register(mContext, defaultDataSub);
+ }
}
@OnLifecycleEvent(ON_PAUSE)
@@ -108,6 +112,21 @@ public class DataDuringCallsPreferenceController extends TelephonyTogglePreferen
|| SubscriptionManager.getDefaultDataSubscriptionId() == subId) {
return CONDITIONALLY_UNAVAILABLE;
}
+ boolean isDefDataEnabled = mManager.createForSubscriptionId(
+ SubscriptionManager.getDefaultDataSubscriptionId())
+ .isDataEnabled();
+ // Do not show 'Data during calls' preference when mobile data switch
+ // for the DDS sub is turned off.
+ if (!isDefDataEnabled) {
+ return CONDITIONALLY_UNAVAILABLE;
+ }
+
+ if (TelephonyUtils.isSubsidyFeatureEnabled(mContext) &&
+ !TelephonyUtils.isSubsidySimCard(mContext,
+ SubscriptionManager.getSlotIndex(mSubId))) {
+ return CONDITIONALLY_UNAVAILABLE;
+ }
+
return AVAILABLE;
}
diff --git a/src/com/android/settings/network/telephony/DefaultSubscriptionController.java b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
index 168e69df2b..1a20f2bb9f 100644
--- a/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
+++ b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java
@@ -21,12 +21,18 @@ import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
import android.content.ComponentName;
import android.content.Context;
+import android.provider.Settings;
+import android.sysprop.TelephonyProperties;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
+import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.view.View;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
@@ -44,6 +50,8 @@ import com.android.settings.network.SubscriptionsChangeListener;
import java.util.ArrayList;
import java.util.List;
+import org.codeaurora.internal.IExtTelephony;
+
/**
* This implements common controller functionality for a Preference letting the user see/change
* what mobile network subscription is used by default for some service controlled by the
@@ -65,12 +73,28 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere
"com.android.services.telephony.TelephonyConnectionService");
private boolean mIsRtlMode;
+ protected TelephonyManager mTelephonyManager;
+
+ //String keys for data preference lookup
+ private static final String LIST_DATA_PREFERENCE_KEY = "data_preference";
+
+ private int mPhoneCount;
+ private PhoneStateListener[] mPhoneStateListener;
+ private int[] mCallState;
+ private ArrayList<SubscriptionInfo> mSelectableSubs;
+
public DefaultSubscriptionController(Context context, String preferenceKey) {
super(context, preferenceKey);
mManager = context.getSystemService(SubscriptionManager.class);
mChangeListener = new SubscriptionsChangeListener(context, this);
mIsRtlMode = context.getResources().getConfiguration().getLayoutDirection()
== View.LAYOUT_DIRECTION_RTL;
+ mTelephonyManager = (TelephonyManager) mContext
+ .getSystemService(Context.TELEPHONY_SERVICE);
+ mPhoneCount = mTelephonyManager.getPhoneCount();
+ mPhoneStateListener = new PhoneStateListener[mPhoneCount];
+ mCallState = new int[mPhoneCount];
+ mSelectableSubs = new ArrayList<SubscriptionInfo>();
}
public void init(Lifecycle lifecycle) {
@@ -94,18 +118,27 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere
@Override
public int getAvailabilityStatus(int subId) {
- return AVAILABLE;
+ boolean visible = false;
+ if (mSelectableSubs != null && mSelectableSubs.size() > 1) {
+ visible = true;
+ } else {
+ visible = false;
+ }
+
+ return visible ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
@OnLifecycleEvent(ON_RESUME)
public void onResume() {
mChangeListener.start();
+ registerPhoneStateListener();
updateEntries();
}
@OnLifecycleEvent(ON_PAUSE)
public void onPause() {
mChangeListener.stop();
+ unRegisterPhoneStateListener();
}
@Override
@@ -139,6 +172,13 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere
if (mPreference == null) {
return;
}
+
+ updateSubStatus();
+ if (mSelectableSubs.isEmpty()) {
+ Log.d(TAG, "updateEntries: mSelectable subs is empty");
+ return;
+ }
+
if (!isAvailable()) {
mPreference.setVisible(false);
return;
@@ -150,24 +190,22 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere
// getAvailabilityStatus returned CONDITIONALLY_UNAVAILABLE at the time.
mPreference.setOnPreferenceChangeListener(this);
- final List<SubscriptionInfo> subs = SubscriptionUtil.getActiveSubscriptions(mManager);
-
// We'll have one entry for each available subscription, plus one for a "ask me every
// time" entry at the end.
final ArrayList<CharSequence> displayNames = new ArrayList<>();
final ArrayList<CharSequence> subscriptionIds = new ArrayList<>();
- if (subs.size() == 1) {
+ if (mSelectableSubs.size() == 1) {
mPreference.setEnabled(false);
mPreference.setSummary(SubscriptionUtil.getUniqueSubscriptionDisplayName(
- subs.get(0), mContext));
+ mSelectableSubs.get(0), mContext));
return;
}
final int serviceDefaultSubId = getDefaultSubscriptionId();
boolean subIsAvailable = false;
- for (SubscriptionInfo sub : subs) {
+ for (SubscriptionInfo sub : mSelectableSubs) {
if (sub.isOpportunistic()) {
continue;
}
@@ -178,14 +216,30 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere
subIsAvailable = true;
}
}
+ if (TextUtils.equals(getPreferenceKey(), LIST_DATA_PREFERENCE_KEY)) {
+ boolean isEcbmEnabled = mTelephonyManager.getEmergencyCallbackMode();
+ boolean isScbmEnabled = TelephonyProperties.in_scbm().orElse(false);
+
+ int isSmartDdsEnabled = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.SMART_DDS_SWITCH, 0);
+
+ if (isSmartDdsEnabled == 0) {
+ mPreference.setEnabled(isCallStateIdle() && !isEcbmEnabled && !isScbmEnabled &&
+ (!TelephonyUtils.isSubsidyFeatureEnabled(mContext) ||
+ TelephonyUtils.allowUsertoSetDDS(mContext)));
+ } else {
+ mPreference.setEnabled(false);
+ mPreference.setSummary("Smart DDS switch is on");
+ }
- if (isAskEverytimeSupported()) {
- // Add the extra "Ask every time" value at the end.
- displayNames.add(mContext.getString(R.string.calls_and_sms_ask_every_time));
- subscriptionIds.add(Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ } else {
+ if (isAskEverytimeSupported()) {
+ // Add the extra "Ask every time" value at the end.
+ displayNames.add(mContext.getString(R.string.calls_and_sms_ask_every_time));
+ subscriptionIds.add(Integer.toString(SubscriptionManager.INVALID_SUBSCRIPTION_ID));
+ }
}
- mPreference.setEnabled(true);
mPreference.setEntries(displayNames.toArray(new CharSequence[0]));
mPreference.setEntryValues(subscriptionIds.toArray(new CharSequence[0]));
@@ -266,6 +320,16 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere
return (label != null) ? label : "";
}
+ private boolean isCallStateIdle() {
+ boolean callStateIdle = true;
+ for (int i = 0; i < mPhoneCount; i++) {
+ if (TelephonyManager.CALL_STATE_IDLE != mCallState[i]) {
+ callStateIdle = false;
+ }
+ }
+ return callStateIdle;
+ }
+
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final int subscriptionId = Integer.parseInt((String) newValue);
@@ -280,6 +344,9 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere
@Override
public void onSubscriptionsChanged() {
+ if (mSelectableSubs != null) mSelectableSubs.clear();
+ updateSubStatus();
+
if (mPreference != null) {
updateEntries();
refreshSummary(mPreference);
@@ -289,4 +356,53 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere
boolean isRtlMode() {
return mIsRtlMode;
}
+
+ private void registerPhoneStateListener() {
+ //To make sure subinfo is added, before registering for call state change
+ updateSubStatus();
+
+ for (int i = 0; i < mSelectableSubs.size(); i++) {
+ int subId = mSelectableSubs.get(i).getSubscriptionId();
+ TelephonyManager tm = mTelephonyManager.createForSubscriptionId(subId);
+ tm.listen(getPhoneStateListener(i),
+ PhoneStateListener.LISTEN_CALL_STATE);
+ }
+ }
+
+ private void unRegisterPhoneStateListener() {
+ for (int i = 0; i < mPhoneCount; i++) {
+ if (mPhoneStateListener[i] != null) {
+ mTelephonyManager.listen(mPhoneStateListener[i], PhoneStateListener.LISTEN_NONE);
+ mPhoneStateListener[i] = null;
+ }
+ }
+ }
+
+ private PhoneStateListener getPhoneStateListener(int phoneId) {
+ // Disable Sim selection for Data when voice call is going on as changing the default data
+ // sim causes a modem reset currently and call gets disconnected
+ final int i = phoneId;
+ mPhoneStateListener[phoneId] = new PhoneStateListener() {
+ @Override
+ public void onCallStateChanged(int state, String incomingNumber) {
+ mCallState[i] = state;
+ updateEntries();
+ }
+ };
+ return mPhoneStateListener[phoneId];
+ }
+
+ private void updateSubStatus() {
+ if (!mSelectableSubs.isEmpty()) {
+ return;
+ }
+
+ for (int i = 0; i < mPhoneCount; ++i) {
+ final SubscriptionInfo sir = mManager
+ .getActiveSubscriptionInfoForSimSlotIndex(i);
+ if (sir != null) {
+ mSelectableSubs.add(sir);
+ }
+ }
+ }
}
diff --git a/src/com/android/settings/network/telephony/Enabled5GPreferenceController.java b/src/com/android/settings/network/telephony/Enabled5GPreferenceController.java
new file mode 100755
index 0000000000..fbd78d7a56
--- /dev/null
+++ b/src/com/android/settings/network/telephony/Enabled5GPreferenceController.java
@@ -0,0 +1,341 @@
+/**
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+package com.android.settings.network.telephony;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PersistableBundle;
+import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
+import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.core.lifecycle.events.OnStop;
+
+import com.android.settings.R;
+import com.android.settings.network.AllowedNetworkTypesListener;
+import com.android.settings.network.telephony.MobileNetworkUtils;
+
+
+/**
+ * Preference controller for "Enabled 5G Switch"
+*/
+public class Enabled5GPreferenceController extends TelephonyTogglePreferenceController
+ implements LifecycleObserver, OnStart, OnStop {
+ private static final String TAG = "Enable5g";
+ private static final int NETWORK_MODE_TYPE_INVALID = -1;
+ private static final String USER_SELECTED_NW_MODE_KEY = "user_selected_network_type_";
+
+ Preference mPreference;
+ private PhoneCallStateListener mPhoneStateListener;
+ private TelephonyManager mTelephonyManager;
+ private AllowedNetworkTypesListener mAllowedNetworkTypesListener;
+ @VisibleForTesting
+ Integer mCallState;
+
+ private ContentObserver mSubsidySettingsObserver;
+ /*
+ * Indicates whether this SUB has NR capability or not.
+ */
+ private boolean mIsNrRadioSupported = false;
+ /*
+ * Indicates whether NR can be registered on both SUBs at the same time.
+ */
+ private boolean mIsDualNrSupported = false;
+
+ private SharedPreferences mSharedPreferences;
+ private boolean mChangedBy5gToggle = false;
+
+ private final BroadcastReceiver mDefaultDataChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mPreference != null) {
+ Log.d(TAG,"DDS is changed");
+ updateState(mPreference);
+ }
+ }
+ };
+ public Enabled5GPreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ public Enabled5GPreferenceController init(int subId) {
+ if (mPhoneStateListener == null) {
+ mPhoneStateListener = new PhoneCallStateListener();
+ }
+
+ if (SubscriptionManager.isValidSubscriptionId(mSubId) && mSubId == subId) {
+ return this;
+ }
+ mSubId = subId;
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(mSubId);
+ mIsNrRadioSupported =
+ checkSupportedRadioBitmask(mTelephonyManager.getSupportedRadioAccessFamily(),
+ TelephonyManager.NETWORK_TYPE_BITMASK_NR);
+ mIsDualNrSupported = TelephonyUtils.isDual5gSupported(mTelephonyManager);
+ if (mAllowedNetworkTypesListener == null) {
+ mAllowedNetworkTypesListener = new AllowedNetworkTypesListener(
+ mContext.getMainExecutor());
+ mAllowedNetworkTypesListener.setAllowedNetworkTypesListener(
+ () -> update());
+ }
+ mSharedPreferences = mContext.getSharedPreferences(mContext.getPackageName(),
+ mContext.MODE_PRIVATE);
+ return this;
+ }
+
+ private void update() {
+ Log.d(TAG, "update.");
+ updatePreference();
+ //if user select network mode from prefered network list, then reset cache to invalid.
+ if (!mChangedBy5gToggle) {
+ cachePreviousSelectedNwType(NETWORK_MODE_TYPE_INVALID);
+ }
+ mChangedBy5gToggle = false;
+ }
+ private void updatePreference() {
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
+ }
+
+ @Override
+ public int getAvailabilityStatus(int subId) {
+ final PersistableBundle carrierConfig = getCarrierConfigForSubId(subId);
+ if (carrierConfig == null || mTelephonyManager == null) {
+ return CONDITIONALLY_UNAVAILABLE;
+ }
+ int defaultDdsSubId = SubscriptionManager.getDefaultDataSubscriptionId();
+ final boolean isSingleNrSupportedOnly =
+ !mIsDualNrSupported && (defaultDdsSubId == subId);
+ final boolean isNrAllowed =
+ checkSupportedRadioBitmask(mTelephonyManager.getAllowedNetworkTypes(),
+ TelephonyManager.NETWORK_TYPE_BITMASK_NR);
+ final boolean isVisible = SubscriptionManager.isValidSubscriptionId(subId)
+ && !carrierConfig.getBoolean(CarrierConfigManager.KEY_HIDE_ENABLED_5G_BOOL)
+ && mIsNrRadioSupported
+ && isNrAllowed
+ && (mIsDualNrSupported || isSingleNrSupportedOnly);
+ return isVisible ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ @Override
+ public void onStart() {
+ mContext.registerReceiver(mDefaultDataChangedReceiver,
+ new IntentFilter(TelephonyIntents.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED));
+ if (mPhoneStateListener != null) {
+ mPhoneStateListener.register(mContext, mSubId);
+ }
+ if (mAllowedNetworkTypesListener != null) {
+ mAllowedNetworkTypesListener.register(mContext, mSubId);
+ }
+ }
+
+ @Override
+ public void onStop() {
+ if (mDefaultDataChangedReceiver != null) {
+ mContext.unregisterReceiver(mDefaultDataChangedReceiver);
+ }
+ if (mPhoneStateListener != null) {
+ mPhoneStateListener.unregister();
+ }
+ if (mAllowedNetworkTypesListener != null) {
+ mAllowedNetworkTypesListener.unregister(mContext, mSubId);
+ }
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+ final SwitchPreference switchPreference = (SwitchPreference) preference;
+ switchPreference.setVisible(isAvailable());
+ long preferredNetworkBitMask = MobileNetworkUtils.getRafFromNetworkType(
+ getAllowedNetworkMode());
+ switchPreference.setChecked(isNrNetworkModeType(preferredNetworkBitMask));
+ switchPreference.setEnabled(isCallStateIdle());
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
+ return false;
+ }
+ int oldNetworkMode = getAllowedNetworkMode();
+ long newNetworkBitMask;
+ if (TelephonyManager.NETWORK_MODE_NR_ONLY != oldNetworkMode) {
+ long oldNetworkBitMask = MobileNetworkUtils.getRafFromNetworkType(oldNetworkMode);
+ if (isChecked) {
+ long networkTypeBitmap4g = oldNetworkBitMask
+ & TelephonyManager.NETWORK_CLASS_BITMASK_4G;
+ long networkTypeBitmap3g = oldNetworkBitMask
+ & TelephonyManager.NETWORK_CLASS_BITMASK_3G;
+ if (networkTypeBitmap4g == 0 && networkTypeBitmap3g == 0) {
+ //Enable from 2G to 5G.
+ //Use NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA as default value
+ //with LTE
+ oldNetworkBitMask = MobileNetworkUtils.getRafFromNetworkType(
+ TelephonyManager.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA);
+ cachePreviousSelectedNwType(oldNetworkMode);
+ } else if(networkTypeBitmap4g == 0) {
+ //Enable from 3G to 5G.
+ //For EVDO only, map to TelephonyManager.NETWORK_MODE_LTE_CDMA_EVDO
+ //as no proper mapping value include LTE.
+ if (oldNetworkMode == TelephonyManager.NETWORK_MODE_EVDO_NO_CDMA) {
+ oldNetworkBitMask = MobileNetworkUtils.getRafFromNetworkType(
+ TelephonyManager.NETWORK_MODE_LTE_CDMA_EVDO);
+ } else {
+ oldNetworkBitMask = oldNetworkBitMask
+ | TelephonyManager.NETWORK_TYPE_BITMASK_LTE;
+ }
+ cachePreviousSelectedNwType(oldNetworkMode);
+ } else {
+ cachePreviousSelectedNwType(NETWORK_MODE_TYPE_INVALID);
+ }
+ }
+ int userSelectedNwMode = getPreviousSelectedNwType();
+ if ((userSelectedNwMode != NETWORK_MODE_TYPE_INVALID) && !isChecked) {
+ Log.d(TAG, "userSelectedNwMode: " + userSelectedNwMode);
+ newNetworkBitMask = MobileNetworkUtils
+ .getRafFromNetworkType(userSelectedNwMode);
+ cachePreviousSelectedNwType(NETWORK_MODE_TYPE_INVALID);
+ } else {
+ newNetworkBitMask = isChecked ?
+ (oldNetworkBitMask | TelephonyManager.NETWORK_TYPE_BITMASK_NR)
+ : (oldNetworkBitMask & ~TelephonyManager.NETWORK_TYPE_BITMASK_NR);
+ }
+ } else {
+ newNetworkBitMask = MobileNetworkUtils
+ .getRafFromNetworkType(TelephonyManager.NETWORK_MODE_LTE_ONLY);
+ }
+ mTelephonyManager.setAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER, newNetworkBitMask);
+ mChangedBy5gToggle = true;
+ return true;
+ }
+
+ private void cachePreviousSelectedNwType(int oldNetworkMode) {
+ Log.d(TAG, "cachePreviousSelectedNwType: " + oldNetworkMode);
+ int slotId = SubscriptionManager.getSlotIndex(mSubId);
+ mSharedPreferences.edit()
+ .putInt(USER_SELECTED_NW_MODE_KEY + slotId, oldNetworkMode).apply();
+ }
+
+ private int getPreviousSelectedNwType() {
+ int slotId = SubscriptionManager.getSlotIndex(mSubId);
+ return mSharedPreferences.getInt(USER_SELECTED_NW_MODE_KEY
+ + slotId, NETWORK_MODE_TYPE_INVALID);
+ }
+
+ private int getAllowedNetworkMode() {
+ return MobileNetworkUtils.getNetworkTypeFromRaf(
+ (int) mTelephonyManager.getAllowedNetworkTypesForReason(
+ TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER));
+ }
+
+ @Override
+ public boolean isChecked(){
+ long preNetworkBitMask = MobileNetworkUtils.getRafFromNetworkType(
+ getAllowedNetworkMode());
+ return isNrNetworkModeType(preNetworkBitMask);
+ }
+
+ private boolean isNrNetworkModeType(long currentRadioBitmask) {
+ return checkSupportedRadioBitmask(currentRadioBitmask,
+ TelephonyManager.NETWORK_TYPE_BITMASK_NR);
+ }
+
+ boolean checkSupportedRadioBitmask(long supportedRadioBitmask, long targetBitmask) {
+ Log.d(TAG, "supportedRadioBitmask: " + supportedRadioBitmask);
+ if ((targetBitmask & supportedRadioBitmask) > 0) {
+ return true;
+ }
+ return false;
+ }
+
+ boolean isCallStateIdle() {
+ boolean callStateIdle = true;
+ if (mCallState != null && mCallState != TelephonyManager.CALL_STATE_IDLE) {
+ callStateIdle = false;
+ }
+ Log.d(TAG, "isCallStateIdle:" + callStateIdle);
+ return callStateIdle;
+ }
+
+ private class PhoneCallStateListener extends PhoneStateListener {
+
+ PhoneCallStateListener() {
+ super(Looper.getMainLooper());
+ }
+
+ private TelephonyManager mTelephonyManager;
+
+ @Override
+ public void onCallStateChanged(int state, String incomingNumber) {
+ mCallState = state;
+ updateState(mPreference);
+ }
+
+ public void register(Context context, int subId) {
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
+ }
+ mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE);
+
+ }
+
+ public void unregister() {
+ mCallState = null;
+ mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE);
+ }
+ }
+}
diff --git a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
index 25e0ae0765..8f4894054c 100644
--- a/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
+++ b/src/com/android/settings/network/telephony/EnabledNetworkModePreferenceController.java
@@ -20,12 +20,18 @@ import static androidx.lifecycle.Lifecycle.Event.ON_START;
import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
import android.os.PersistableBundle;
+import android.provider.Settings;
import android.telephony.CarrierConfigManager;
+import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.Log;
+import androidx.annotation.VisibleForTesting;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
@@ -59,6 +65,9 @@ public class EnabledNetworkModePreferenceController extends
private CarrierConfigManager mCarrierConfigManager;
private PreferenceEntriesBuilder mBuilder;
private SubscriptionsChangeListener mSubscriptionsListener;
+ private PhoneCallStateListener mPhoneStateListener;
+ @VisibleForTesting
+ Integer mCallState;
public EnabledNetworkModePreferenceController(Context context, String key) {
super(context, key);
@@ -94,6 +103,10 @@ public class EnabledNetworkModePreferenceController extends
if (mAllowedNetworkTypesListener == null) {
return;
}
+ if (mPhoneStateListener != null) {
+ mPhoneStateListener.register(mContext, mSubId);
+ }
+
mAllowedNetworkTypesListener.register(mContext, mSubId);
}
@@ -103,6 +116,9 @@ public class EnabledNetworkModePreferenceController extends
if (mAllowedNetworkTypesListener == null) {
return;
}
+ if (mPhoneStateListener != null) {
+ mPhoneStateListener.unregister();
+ }
mAllowedNetworkTypesListener.unregister(mContext, mSubId);
}
@@ -125,6 +141,7 @@ public class EnabledNetworkModePreferenceController extends
listPreference.setEntryValues(mBuilder.getEntryValues());
listPreference.setValue(Integer.toString(mBuilder.getSelectedEntryValue()));
listPreference.setSummary(mBuilder.getSummary());
+ listPreference.setEnabled(isCallStateIdle());
}
@Override
@@ -148,6 +165,9 @@ public class EnabledNetworkModePreferenceController extends
.createForSubscriptionId(mSubId);
mBuilder = new PreferenceEntriesBuilder(mContext, mSubId);
+ if (mPhoneStateListener == null) {
+ mPhoneStateListener = new PhoneCallStateListener();
+ }
if (mAllowedNetworkTypesListener == null) {
mAllowedNetworkTypesListener = new AllowedNetworkTypesListener(
mContext.getMainExecutor());
@@ -353,7 +373,7 @@ public class EnabledNetworkModePreferenceController extends
if (entryValuesInt.length < 3) {
throw new IllegalArgumentException("ENABLED_NETWORKS_CHOICES index error.");
}
- add5gEntry(addNrToLteNetworkType(entryValuesInt[0]));
+ add5gLteEntry(addNrToLteNetworkType(entryValuesInt[0]));
addLteEntry(entryValuesInt[0]);
add3gEntry(entryValuesInt[1]);
add2gEntry(entryValuesInt[2]);
@@ -589,7 +609,9 @@ public class EnabledNetworkModePreferenceController extends
case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_WCDMA:
setSelectedEntry(
TelephonyManagerConstants.NETWORK_MODE_NR_LTE_GSM_WCDMA);
- setSummary(getResourcesForSubId().getString(R.string.network_5G_recommended));
+ setSummary((mShow4gForLTE ? getResourcesForSubId().getString(R.string.network_5G_recommended)
+ : getResourcesForSubId().getString(R.string.network_5G_lte))
+ + getResourcesForSubId().getString(R.string.network_5G_recommended));
break;
case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA:
case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_GSM:
@@ -598,11 +620,15 @@ public class EnabledNetworkModePreferenceController extends
case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
setSelectedEntry(TelephonyManagerConstants
.NETWORK_MODE_NR_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA);
- setSummary(getResourcesForSubId().getString(R.string.network_5G_recommended));
+ setSummary((mShow4gForLTE ? getResourcesForSubId().getString(R.string.network_5G_recommended)
+ : getResourcesForSubId().getString(R.string.network_5G_lte))
+ + getResourcesForSubId().getString(R.string.network_5G_recommended));
break;
case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO:
setSelectedEntry(TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO);
- setSummary(getResourcesForSubId().getString(R.string.network_5G_recommended));
+ setSummary((mShow4gForLTE ? getResourcesForSubId().getString(R.string.network_5G_recommended)
+ : getResourcesForSubId().getString(R.string.network_5G_lte))
+ + getResourcesForSubId().getString(R.string.network_5G_recommended));
break;
case TelephonyManagerConstants.NETWORK_MODE_NR_LTE_CDMA_EVDO_GSM_WCDMA:
setSelectedEntry(
@@ -612,8 +638,9 @@ public class EnabledNetworkModePreferenceController extends
|| MobileNetworkUtils.isWorldMode(mContext, mSubId)) {
setSummary(R.string.network_global);
} else {
- setSummary(getResourcesForSubId().getString(
- R.string.network_5G_recommended));
+ setSummary((mShow4gForLTE ? getResourcesForSubId().getString(R.string.network_5G_recommended)
+ : getResourcesForSubId().getString(R.string.network_5G_lte))
+ + getResourcesForSubId().getString(R.string.network_5G_recommended));
}
break;
default:
@@ -717,6 +744,23 @@ public class EnabledNetworkModePreferenceController extends
}
}
+ // This entry is used to support for 5G/LTE display in resource overlay
+ private void add5gLteEntry(int value) {
+ boolean isNRValue = value >= TelephonyManagerConstants.NETWORK_MODE_NR_ONLY;
+ if (showNrList() && isNRValue) {
+ mEntries.add(mContext.getString(R.string.network_5G_lte)
+ + mContext.getString(R.string.network_5G_recommended));
+ mEntriesValue.add(value);
+ mIs5gEntryDisplayed = true;
+ } else {
+ mIs5gEntryDisplayed = false;
+ Log.d(LOG_TAG, "Hide 5G option. "
+ + " supported5GRadioAccessFamily: " + mSupported5gRadioAccessFamily
+ + " allowed5GNetworkType: " + mAllowed5gNetworkType
+ + " isNRValue: " + isNRValue);
+ }
+ }
+
private void addGlobalEntry(int value) {
Log.d(LOG_TAG, "addGlobalEntry. "
+ " supported5GRadioAccessFamily: " + mSupported5gRadioAccessFamily
@@ -836,4 +880,42 @@ public class EnabledNetworkModePreferenceController extends
public void onSubscriptionsChanged() {
mBuilder.updateConfig();
}
+
+ private boolean isCallStateIdle() {
+ boolean callStateIdle = true;
+ if (mCallState != null && mCallState != TelephonyManager.CALL_STATE_IDLE) {
+ callStateIdle = false;
+ }
+ Log.d(LOG_TAG, "isCallStateIdle:" + callStateIdle);
+ return callStateIdle;
+ }
+
+ private class PhoneCallStateListener extends PhoneStateListener {
+
+ PhoneCallStateListener() {
+ super(Looper.getMainLooper());
+ }
+
+ private TelephonyManager mTelephonyManager;
+
+ @Override
+ public void onCallStateChanged(int state, String incomingNumber) {
+ mCallState = state;
+ updateState(mPreference);
+ }
+
+ public void register(Context context, int subId) {
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
+ }
+ mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE);
+
+ }
+
+ public void unregister() {
+ mCallState = null;
+ mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE);
+ }
+ }
}
diff --git a/src/com/android/settings/network/telephony/LegacyIncrementalScanBroadcastReceiver.java b/src/com/android/settings/network/telephony/LegacyIncrementalScanBroadcastReceiver.java
new file mode 100644
index 0000000000..a72f691d93
--- /dev/null
+++ b/src/com/android/settings/network/telephony/LegacyIncrementalScanBroadcastReceiver.java
@@ -0,0 +1,220 @@
+/**
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.android.settings.network.telephony;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.telephony.CellInfo;
+import android.telephony.CellInfoGsm;
+import android.telephony.NetworkScan;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.telephony.TelephonyScanManager;
+import android.util.Log;
+
+import com.android.internal.telephony.OperatorInfo;
+import com.android.settings.Utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class receives the incremental scan results intent from QCRIL Message Tunnel, processes it
+ * and sends them to the network search results activity {@link NetworkSelectSettings.java}.
+ */
+
+public class LegacyIncrementalScanBroadcastReceiver extends BroadcastReceiver {
+ private static final String TAG = "LegacyIncrementalScanBroadcastReceiver";
+ private static final String ACTION_INCREMENTAL_NW_SCAN_IND
+ = "qualcomm.intent.action.ACTION_INCREMENTAL_NW_SCAN_IND";
+
+ private static final String EXTRA_SCAN_RESULT = "scan_result";
+ private static final String EXTRA_INCREMENTAL_SCAN_DATA = "incr_nw_scan_data";
+ private static final String EXTRA_INSTANCE_ID = "sub_id";
+
+ private static final int QUERY_EXCEPTION = -1;
+
+ // Network scan was successful and complete
+ private static final int NAS_QUERY_COMPLETE = 0;
+ // Network scan was partial
+ private static final int NAS_QUERY_PARTIAL = 1;
+ // Network scan was aborted
+ private static final int NAS_QUERY_ABORT = 2;
+ // Network scan did not complete due to a radio link failure recovery in progress
+ private static final int NAS_QUERY_REJ_IN_RLF = 3;
+ // Sending incremental network scan errors
+ private static final int NAS_QUERY_INCREMENT_ERROR = 4;
+ // Periodic network scan gave partial results
+ private static final int NAS_QUERY_PARTIAL_PERIODIC = 5;
+
+ private static int sPhoneCount;
+ private Context mContext;
+
+ // QueryDetails for each phoneId
+ private QueryDetails[] mQueryDetails;
+
+ private final TelephonyScanManager.NetworkScanCallback mNetworkScanCallback;
+
+ // TODO: This class may not be required since handling of incremental results is already
+ // being taken care of in {@link NetworkSelectSettings} class.
+ class QueryDetails {
+ String[] storedScanInfo;
+
+ QueryDetails() {
+ storedScanInfo = null;
+ }
+
+ void concatScanInfo(String[] scanInfo) {
+ String[] concatScanInfo = new String[storedScanInfo.length + scanInfo.length];
+ System.arraycopy(storedScanInfo, 0, concatScanInfo, 0, storedScanInfo.length);
+ System.arraycopy(scanInfo, 0, concatScanInfo, storedScanInfo.length,
+ scanInfo.length);
+ storedScanInfo = concatScanInfo;
+ }
+
+ void reset() {
+ storedScanInfo = null;
+ }
+ }
+
+ public LegacyIncrementalScanBroadcastReceiver(Context context,
+ TelephonyScanManager.NetworkScanCallback mInternalNetworkScanCallback) {
+ mContext = context;
+ TelephonyManager tm =
+ (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ sPhoneCount = tm.getActiveModemCount();
+ mQueryDetails = new QueryDetails[sPhoneCount];
+ for (int i = 0; i < sPhoneCount; i++) {
+ mQueryDetails[i] = new QueryDetails();
+ }
+ mNetworkScanCallback = mInternalNetworkScanCallback;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "onReceive " + intent);
+ if (ACTION_INCREMENTAL_NW_SCAN_IND.equals(intent.getAction())) {
+ broadcastIncrementalQueryResults(intent);
+ }
+ }
+
+ private void onResults(List<CellInfo> results) {
+ mNetworkScanCallback.onResults(results);
+ }
+
+ private void onComplete() {
+ mNetworkScanCallback.onComplete();
+ }
+
+ private void onError(int error) {
+ mNetworkScanCallback.onError(error);
+ }
+
+ private void broadcastIncrementalQueryResults(Intent intent) {
+ int result = intent.getIntExtra(EXTRA_SCAN_RESULT, QUERY_EXCEPTION);
+ int phoneId = intent.getIntExtra(EXTRA_INSTANCE_ID,
+ SubscriptionManager.INVALID_SIM_SLOT_INDEX);
+
+ Log.d(TAG, "broadcastIncrementalQueryResults: phoneid: " + phoneId + ", result: " + result);
+
+ if (phoneId < 0 || phoneId >= sPhoneCount) {
+ // Invalid phoneId
+ onError(NetworkScan.ERROR_INVALID_SCAN);
+ return;
+ }
+
+ if (result == NAS_QUERY_REJ_IN_RLF) {
+ onError(NetworkScan.ERROR_RADIO_INTERFACE_ERROR);
+ return;
+ }
+
+ if (result == NAS_QUERY_ABORT) {
+ onError(NetworkScan.ERROR_MODEM_ERROR);
+ return;
+ }
+
+ if (result == NAS_QUERY_COMPLETE || result == NAS_QUERY_PARTIAL) {
+ String[] scanInfo = intent.getStringArrayExtra(EXTRA_INCREMENTAL_SCAN_DATA);
+ QueryDetails queryDetails = mQueryDetails[phoneId];
+
+ Log.d(TAG, "broadcastIncrementalQueryResults"
+ + ", scanInfo.length: " + (scanInfo == null ? 0 : scanInfo.length));
+
+ if (queryDetails.storedScanInfo != null && scanInfo != null) {
+ queryDetails.concatScanInfo(scanInfo);
+ } else {
+ queryDetails.storedScanInfo = scanInfo;
+ }
+
+ if (queryDetails.storedScanInfo != null) {
+ List<CellInfo> cellInfos = getCellInfosFromScanResult(queryDetails.storedScanInfo);
+ onResults(cellInfos);
+ }
+
+ if (result == NAS_QUERY_COMPLETE) {
+ // Clear the cache, otherwise the results for the next scan will be combined with
+ // the current one.
+ queryDetails.reset();
+ onComplete();
+ }
+ }
+ }
+
+ private List<CellInfo> getCellInfosFromScanResult(String[] scanInfos) {
+ Log.d(TAG, "Number of operators: " + (scanInfos.length)/4);
+ List<CellInfo> cellInfoList = new ArrayList<CellInfo>();
+ if (scanInfos.length >= 4 && (scanInfos.length % 4 == 0)) {
+ // The scan results are grouped into four elements per operator.
+ for (int i = 0; i < scanInfos.length / 4; i++) {
+ int j = 4 * i;
+ String operatorAlphaLong = scanInfos[0 + j];
+ String operatorAlphaShort = scanInfos[1 + j];
+ String operatorNumeric = scanInfos[2 + j];
+ String operatorStateString = scanInfos[3 + j];
+
+ OperatorInfo operatorInfo = new OperatorInfo(operatorAlphaLong,
+ operatorAlphaShort,
+ operatorNumeric,
+ operatorStateString);
+
+ CellInfo cellinfo =
+ CellInfoUtil.convertLegacyIncrScanOperatorInfoToCellInfo(operatorInfo);
+
+ Log.d(TAG, "OperatorInfo: " + operatorInfo.toString()
+ + " CellInfo: " + CellInfoUtil.cellInfoToString(cellinfo));
+
+ cellInfoList.add(cellinfo);
+ }
+ }
+ return cellInfoList;
+ }
+}
diff --git a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
index 1ac121e56f..aaba307603 100644
--- a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
+++ b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java
@@ -21,6 +21,7 @@ import android.os.Handler;
import android.os.Looper;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -32,11 +33,16 @@ import androidx.preference.SwitchPreference;
import com.android.settings.R;
import com.android.settings.network.MobileDataContentObserver;
+import com.android.settings.network.SubscriptionUtil;
import com.android.settings.wifi.WifiPickerTrackerHelper;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
/**
* Preference controller for "Mobile data"
*/
@@ -56,6 +62,7 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon
boolean mNeedDialog;
private WifiPickerTrackerHelper mWifiPickerTrackerHelper;
+ private AnotherSubCallStateListener mCallStateListener;
public MobileDataPreferenceController(Context context, String key) {
super(context, key);
@@ -81,6 +88,10 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon
public void onStart() {
if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
mDataContentObserver.register(mContext, mSubId);
+ // Listen if voice call is on nDDS SUB.
+ if (mSubId == mSubscriptionManager.getDefaultDataSubscriptionId()) {
+ mCallStateListener.register(mContext, mSubId);
+ }
}
}
@@ -88,6 +99,7 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon
public void onStop() {
if (mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
mDataContentObserver.unRegister(mContext);
+ mCallStateListener.unregister();
}
}
@@ -132,8 +144,20 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon
preference.setEnabled(false);
preference.setSummary(R.string.mobile_data_settings_summary_auto_switch);
} else {
- preference.setEnabled(true);
- preference.setSummary(R.string.mobile_data_settings_summary);
+ if (!mCallStateListener.isIdle()) {
+ preference.setEnabled(false);
+ preference.setSummary(
+ R.string.mobile_data_settings_summary_default_data_unavailable);
+ } else {
+ if (TelephonyUtils.isSubsidyFeatureEnabled(mContext) &&
+ !TelephonyUtils.isSubsidySimCard(mContext,
+ mSubscriptionManager.getSlotIndex(mSubId))) {
+ preference.setEnabled(false);
+ } else {
+ preference.setEnabled(true);
+ }
+ preference.setSummary(R.string.mobile_data_settings_summary);
+ }
}
if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
@@ -154,6 +178,10 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon
mSubId = subId;
mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
.createForSubscriptionId(mSubId);
+ mCallStateListener =
+ new AnotherSubCallStateListener(mTelephonyManager,
+ mSubscriptionManager,
+ ()-> updateState(mPreference));
}
public void setWifiPickerTrackerHelper(WifiPickerTrackerHelper helper) {
@@ -165,8 +193,14 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon
final boolean enableData = !isChecked();
final boolean isMultiSim = (mTelephonyManager.getActiveModemCount() > 1);
final int defaultSubId = mSubscriptionManager.getDefaultDataSubscriptionId();
- final boolean needToDisableOthers = mSubscriptionManager
+ boolean needToDisableOthers = mSubscriptionManager
.isActiveSubscriptionId(defaultSubId) && defaultSubId != mSubId;
+ if (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_voice_data_sms_auto_fallback)) {
+ // Mobile data of both subscriptions can be enabled
+ // simultaneously. DDS setting will be controlled by the config.
+ needToDisableOthers = false;
+ }
if (enableData && isMultiSim && needToDisableOthers) {
mDialogType = MobileDataDialogFragment.TYPE_MULTI_SIM_DIALOG;
return true;
@@ -179,4 +213,53 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon
mSubId);
dialogFragment.show(mFragmentManager, DIALOG_TAG);
}
+
+ private static class AnotherSubCallStateListener extends TelephonyCallback
+ implements TelephonyCallback.CallStateListener {
+ private Runnable mRunnable;
+ private int mState = TelephonyManager.CALL_STATE_IDLE;
+ private Map<Integer, AnotherSubCallStateListener> mCallbacks;
+ private TelephonyManager mTelephonyManager;
+ private SubscriptionManager mSubscriptionManager;
+
+ public AnotherSubCallStateListener(TelephonyManager tm, SubscriptionManager sm,
+ Runnable runnable) {
+ mTelephonyManager = tm;
+ mSubscriptionManager = sm;
+ mRunnable = runnable;
+ mCallbacks = new TreeMap<>();
+ }
+
+ public void register(Context context, int subId) {
+ final List<SubscriptionInfo> subs =
+ SubscriptionUtil.getActiveSubscriptions(mSubscriptionManager);
+ for (SubscriptionInfo subInfo : subs) {
+ if (subInfo.getSubscriptionId() != subId) {
+ mTelephonyManager.createForSubscriptionId(subInfo.getSubscriptionId())
+ .registerTelephonyCallback(context.getMainExecutor(), this);
+ mCallbacks.put(subInfo.getSubscriptionId(), this);
+ }
+ }
+ }
+
+ public void unregister() {
+ for (int subId : mCallbacks.keySet()) {
+ mTelephonyManager.createForSubscriptionId(subId)
+ .unregisterTelephonyCallback(mCallbacks.get(subId));
+ }
+ mCallbacks.clear();
+ }
+
+ public boolean isIdle() {
+ return mState == TelephonyManager.CALL_STATE_IDLE;
+ }
+
+ @Override
+ public void onCallStateChanged(int state) {
+ mState = state;
+ if (mRunnable != null) {
+ mRunnable.run();
+ }
+ }
+ }
}
diff --git a/src/com/android/settings/network/telephony/MobileDataSlice.java b/src/com/android/settings/network/telephony/MobileDataSlice.java
index 22bb5818f9..d36ab616e5 100644
--- a/src/com/android/settings/network/telephony/MobileDataSlice.java
+++ b/src/com/android/settings/network/telephony/MobileDataSlice.java
@@ -69,7 +69,15 @@ public class MobileDataSlice implements CustomSliceable {
public MobileDataSlice(Context context) {
mContext = context;
mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
- mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+
+ // Fix: make sure using the same subId when get and set mobile data status
+ final int defaultSubId = getDefaultSubscriptionId(mSubscriptionManager);
+ if (SubscriptionManager.INVALID_SUBSCRIPTION_ID != defaultSubId) {
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(defaultSubId);
+ } else {
+ mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
+ }
}
@Override
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index ba80a8ce65..da22f98b3f 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -18,11 +18,17 @@ package com.android.settings.network.telephony;
import android.app.Activity;
import android.app.settings.SettingsEnums;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserManager;
+import android.provider.SearchIndexableResource;
import android.provider.Settings;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -34,6 +40,8 @@ import android.view.MenuItem;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.TelephonyIntents;
import com.android.settings.R;
import com.android.settings.datausage.BillingCyclePreferenceController;
import com.android.settings.datausage.DataUsageSummaryPreferenceController;
@@ -49,6 +57,8 @@ import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.utils.ThreadUtils;
+import org.codeaurora.internal.IExtTelephony;
+
import java.util.Arrays;
import java.util.List;
@@ -61,12 +71,17 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
@VisibleForTesting
static final String KEY_CLICKED_PREF = "key_clicked_pref";
+ // UICC provisioning status
+ public static final int CARD_NOT_PROVISIONED = 0;
+ public static final int CARD_PROVISIONED = 1;
+
//String keys for preference lookup
private static final String BUTTON_CDMA_SYSTEM_SELECT_KEY = "cdma_system_select_key";
private static final String BUTTON_CDMA_SUBSCRIPTION_KEY = "cdma_subscription_key";
private TelephonyManager mTelephonyManager;
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ private int mPhoneId = SubscriptionManager.INVALID_PHONE_INDEX;
private CdmaSystemSelectPreferenceController mCdmaSystemSelectPreferenceController;
private CdmaSubscriptionPreferenceController mCdmaSubscriptionPreferenceController;
@@ -78,6 +93,33 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
private boolean mDropFirstSubscriptionChangeNotify;
private int mActiveSubscriptionsListenerCount;
+ private final BroadcastReceiver mSimStateReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)) {
+ String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
+ Log.d(LOG_TAG, "Received ACTION_SIM_STATE_CHANGED: " + state);
+ setScreenState();
+ }
+ }
+ };
+
+ private void setScreenState() {
+ int simState = mTelephonyManager.getSimState();
+ boolean screenState = simState != TelephonyManager.SIM_STATE_ABSENT;
+ if (screenState) {
+ SubscriptionManager subscriptionManager = ((SubscriptionManager) getContext().
+ getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE));
+ SubscriptionInfo subInfo = subscriptionManager.getActiveSubscriptionInfo(mSubId);
+ Log.d(LOG_TAG, "subInfo: " + subInfo + ", mSubId: " + mSubId);
+ if (subInfo != null && !subInfo.areUiccApplicationsEnabled()) {
+ screenState = false;
+ }
+ }
+ Log.d(LOG_TAG, "Setting screen state to: " + screenState);
+ getPreferenceScreen().setEnabled(screenState);
+ }
+
public MobileNetworkSettings() {
super(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS);
}
@@ -117,7 +159,8 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
mSubId = getArguments().getInt(Settings.EXTRA_SUB_ID,
MobileNetworkUtils.getSearchableSubscriptionId(context));
- Log.i(LOG_TAG, "display subId: " + mSubId);
+ mPhoneId = SubscriptionManager.getPhoneId(mSubId);
+ Log.i(LOG_TAG, "display subId: " + mSubId + ", phoneId: " + mPhoneId);
if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
return Arrays.asList();
@@ -136,6 +179,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
if (dataUsageSummaryPreferenceController != null) {
dataUsageSummaryPreferenceController.init(mSubId);
}
+ use(DataDefaultSubscriptionController.class).init(getLifecycle());
use(CallsDefaultSubscriptionController.class).init(getLifecycle());
use(SmsDefaultSubscriptionController.class).init(getLifecycle());
use(MobileNetworkSwitchController.class).init(getLifecycle(), mSubId);
@@ -154,9 +198,10 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
null /* WifiPickerTrackerCallback */));
use(RoamingPreferenceController.class).init(getFragmentManager(), mSubId);
use(ApnPreferenceController.class).init(mSubId);
+ use(UserPLMNPreferenceController.class).init(mSubId);
use(CarrierPreferenceController.class).init(mSubId);
use(DataUsagePreferenceController.class).init(mSubId);
- use(PreferredNetworkModePreferenceController.class).init(mSubId);
+ use(PreferredNetworkModePreferenceController.class).init(getLifecycle(), mSubId);
use(EnabledNetworkModePreferenceController.class).init(getLifecycle(), mSubId);
use(DataServiceSetupPreferenceController.class).init(mSubId);
use(Enable2gPreferenceController.class).init(mSubId);
@@ -182,6 +227,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
use(VideoCallingPreferenceController.class).init(mSubId);
final BackupCallingPreferenceController crossSimCallingPreferenceController =
use(BackupCallingPreferenceController.class).init(mSubId);
+ use(Enabled5GPreferenceController.class).init(mSubId);
use(CallingPreferenceCategoryController.class).setChildren(
Arrays.asList(wifiCallingPreferenceController, videoCallingPreferenceController,
crossSimCallingPreferenceController));
@@ -216,6 +262,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
@Override
public void onResume() {
+ Log.i(LOG_TAG, "onResume:+");
super.onResume();
// TODO: remove log after fixing b/182326102
Log.d(LOG_TAG, "onResume() subId=" + mSubId);
@@ -229,6 +276,14 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
mDropFirstSubscriptionChangeNotify = true;
}
mActiveSubscriptionsListener.start();
+
+ Context context = getContext();
+ if (context != null) {
+ context.registerReceiver(mSimStateReceiver,
+ new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
+ } else {
+ Log.i(LOG_TAG, "context is null, not registering SimStateReceiver");
+ }
}
private void onSubscriptionDetailChanged() {
@@ -256,6 +311,18 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
super.onDestroy();
}
+ @Override
+ public void onPause() {
+ Log.i(LOG_TAG, "onPause:+");
+ super.onPause();
+ Context context = getContext();
+ if (context != null) {
+ context.unregisterReceiver(mSimStateReceiver);
+ } else {
+ Log.i(LOG_TAG, "context already null, not unregistering SimStateReceiver");
+ }
+ }
+
@VisibleForTesting
void onRestoreInstance(Bundle icicle) {
if (icicle != null) {
@@ -332,6 +399,11 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.mobile_network_settings) {
+ @Override
+ public List<SearchIndexableResource> getXmlResourcesToIndex(Context context,
+ boolean enabled) {
+ return super.getXmlResourcesToIndex(context, enabled);
+ }
/** suppress full page if user is not admin */
@Override
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java
index 0be61e569c..4610b7f4bb 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSwitchController.java
@@ -18,10 +18,17 @@ package com.android.settings.network.telephony;
import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
+import static androidx.lifecycle.Lifecycle.Event.ON_DESTROY;
import android.content.Context;
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.sysprop.TelephonyProperties;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.util.Log;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
@@ -42,12 +49,27 @@ public class MobileNetworkSwitchController extends BasePreferenceController impl
private int mSubId;
private SubscriptionsChangeListener mChangeListener;
private SubscriptionManager mSubscriptionManager;
+ private TelephonyManager mTelephonyManager;
+ private SubscriptionInfo mSubInfo = null;
+ private Context mContext;
+ private int mCallState;
+ private boolean isReceiverRegistered = false;
+
public MobileNetworkSwitchController(Context context, String preferenceKey) {
super(context, preferenceKey);
+ mContext = context;
mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
mChangeListener = new SubscriptionsChangeListener(context, this);
+ mTelephonyManager = (TelephonyManager) mContext
+ .getSystemService(Context.TELEPHONY_SERVICE);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
+ mContext.registerReceiver(mIntentReceiver, filter);
+ isReceiverRegistered = true;
+ mCallState = mTelephonyManager.getCallState();
}
public void init(Lifecycle lifecycle, int subId) {
@@ -66,6 +88,14 @@ public class MobileNetworkSwitchController extends BasePreferenceController impl
mChangeListener.stop();
}
+ @OnLifecycleEvent(ON_DESTROY)
+ public void onDestroy() {
+ if(isReceiverRegistered) {
+ mContext.unregisterReceiver(mIntentReceiver);
+ isReceiverRegistered = false;
+ }
+ }
+
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
@@ -75,6 +105,8 @@ public class MobileNetworkSwitchController extends BasePreferenceController impl
mSwitchBar.setOnBeforeCheckedChangeListener((toggleSwitch, isChecked) -> {
// TODO b/135222940: re-evaluate whether to use
// mSubscriptionManager#isSubscriptionEnabled
+ int phoneId = mSubscriptionManager.getSlotIndex(mSubId);
+ Log.d(TAG, "displayPreference: mSubId=" + mSubId + ", mSubInfo=" + mSubInfo);
if (mSubscriptionManager.isActiveSubscriptionId(mSubId) != isChecked) {
SubscriptionUtil.startToggleSubscriptionDialogActivity(mContext, mSubId, isChecked);
return true;
@@ -89,21 +121,39 @@ public class MobileNetworkSwitchController extends BasePreferenceController impl
return;
}
- SubscriptionInfo subInfo = null;
+ if (mTelephonyManager.getActiveModemCount() == 1 && !mSubscriptionManager.
+ canDisablePhysicalSubscription()) {
+ Log.d(TAG, "update: Hide SIM option for 1.4 HAL in single sim");
+ mSwitchBar.hide();
+ return;
+ }
+
for (SubscriptionInfo info : SubscriptionUtil.getAvailableSubscriptions(mContext)) {
if (info.getSubscriptionId() == mSubId) {
- subInfo = info;
+ mSubInfo = info;
break;
}
}
+ boolean isEcbmEnabled = mTelephonyManager.getEmergencyCallbackMode();
+ boolean isScbmEnabled = TelephonyProperties.in_scbm().orElse(false);
+ if ((TelephonyManager.CALL_STATE_IDLE != mCallState) || isEcbmEnabled || isScbmEnabled) {
+ Log.d(TAG, "update: disable switchbar, isEcbmEnabled=" + isEcbmEnabled +
+ ", isScbmEnabled=" + isScbmEnabled + ", mCallState=" + mCallState);
+ mSwitchBar.setSwitchBarEnabled(false);
+ } else {
+ mSwitchBar.setSwitchBarEnabled(true);
+ }
+
// For eSIM, we always want the toggle. If telephony stack support disabling a pSIM
// directly, we show the toggle.
- if (subInfo == null || (!subInfo.isEmbedded() && !SubscriptionUtil.showToggleForPhysicalSim(
- mSubscriptionManager))) {
+ if (mSubInfo == null) {
mSwitchBar.hide();
} else {
mSwitchBar.show();
+ Log.d(TAG, "update(): mSubId=" + mSubId +
+ ", isActiveSubscriptionId=" +
+ mSubscriptionManager.isActiveSubscriptionId(mSubId));
mSwitchBar.setCheckedInternal(mSubscriptionManager.isActiveSubscriptionId(mSubId));
}
}
@@ -122,4 +172,17 @@ public class MobileNetworkSwitchController extends BasePreferenceController impl
public void onSubscriptionsChanged() {
update();
}
+
+ private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
+ mCallState = mTelephonyManager.getCallState();
+ Log.d(TAG, "onReceive: mCallState= " + mCallState + ", mSubId=" + mSubId);
+ update();
+ }
+ }
+ };
+
}
diff --git a/src/com/android/settings/network/telephony/NetworkOperatorPreference.java b/src/com/android/settings/network/telephony/NetworkOperatorPreference.java
index 3a7dc31c10..f4e13712a3 100644
--- a/src/com/android/settings/network/telephony/NetworkOperatorPreference.java
+++ b/src/com/android/settings/network/telephony/NetworkOperatorPreference.java
@@ -40,6 +40,7 @@ import androidx.preference.Preference;
import com.android.internal.telephony.OperatorInfo;
import com.android.settings.R;
+import com.android.settings.Utils;
import java.util.List;
import java.util.Objects;
@@ -59,7 +60,7 @@ public class NetworkOperatorPreference extends Preference {
private List<String> mForbiddenPlmns;
private int mLevel = LEVEL_NONE;
private boolean mShow4GForLTE;
- private boolean mUseNewApi;
+ private boolean mIsAdvancedScanSupported;
public NetworkOperatorPreference(Context context, CellInfo cellinfo,
List<String> forbiddenPlmns, boolean show4GForLTE) {
@@ -78,8 +79,8 @@ public class NetworkOperatorPreference extends Preference {
super(context);
mForbiddenPlmns = forbiddenPlmns;
mShow4GForLTE = show4GForLTE;
- mUseNewApi = context.getResources().getBoolean(
- com.android.internal.R.bool.config_enableNewAutoSelectNetworkUI);
+ mIsAdvancedScanSupported = TelephonyUtils.isAdvancedPlmnScanSupported(context);
+ Log.d(TAG, "mIsAdvancedScanSupported: " + mIsAdvancedScanSupported);
}
/**
@@ -253,7 +254,7 @@ public class NetworkOperatorPreference extends Preference {
}
private void updateIcon(int level) {
- if (!mUseNewApi || level < 0 || level >= NUM_SIGNAL_STRENGTH_BINS) {
+ if (!mIsAdvancedScanSupported || level < 0 || level >= NUM_SIGNAL_STRENGTH_BINS) {
return;
}
final Context context = getContext();
diff --git a/src/com/android/settings/network/telephony/NetworkScanHelper.java b/src/com/android/settings/network/telephony/NetworkScanHelper.java
index 740b6bba2b..cd686db046 100644
--- a/src/com/android/settings/network/telephony/NetworkScanHelper.java
+++ b/src/com/android/settings/network/telephony/NetworkScanHelper.java
@@ -17,6 +17,10 @@
package com.android.settings.network.telephony;
import android.annotation.IntDef;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.CellInfo;
import android.telephony.NetworkScan;
@@ -29,14 +33,6 @@ import android.util.Log;
import androidx.annotation.VisibleForTesting;
-import com.android.internal.telephony.CellNetworkScanResult;
-
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.SettableFuture;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -88,20 +84,10 @@ public class NetworkScanHelper {
}
@Retention(RetentionPolicy.SOURCE)
- @IntDef({NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS, NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS})
+ @IntDef({NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS, NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS_LEGACY})
public @interface NetworkQueryType {}
/**
- * Performs the network scan using {@link TelephonyManager#getAvailableNetworks()}. The network
- * scan results won't be returned to the caller until the network scan is completed.
- *
- * <p> This is typically used when the modem doesn't support the new network scan api
- * {@link TelephonyManager#requestNetworkScan(
- * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}.
- */
- public static final int NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS = 1;
-
- /**
* Performs the network scan using {@link TelephonyManager#requestNetworkScan(
* NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)} The network scan
* results will be returned to the caller periodically in a small time window until the network
@@ -112,7 +98,18 @@ public class NetworkScanHelper {
* {@link TelephonyManager#requestNetworkScan(
* NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}
*/
- public static final int NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS = 2;
+ public static final int NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS = 1;
+
+ /**
+ * Performs the network scan using {@link IExtTelephony#performIncrementalScan(int)}
+ * The network scan is triggered using QcRil hooks, and the results will be returned to the
+ * caller periodically in a small time window until the network scan is completed.
+ *
+ * <p> This is recommended to be used if modem does not support the new network scan api
+ * {@link TelephonyManager#requestNetworkScan(
+ * NetworkScanRequest, Executor, TelephonyScanManager.NetworkScanCallback)}.
+ */
+ public static final int NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS_LEGACY = 2;
/** The constants below are used in the async network scan. */
@VisibleForTesting
@@ -120,7 +117,7 @@ public class NetworkScanHelper {
@VisibleForTesting
static final int SEARCH_PERIODICITY_SEC = 5;
@VisibleForTesting
- static final int MAX_SEARCH_TIME_SEC = 300;
+ static final int MAX_SEARCH_TIME_SEC = 254;
@VisibleForTesting
static final int INCREMENTAL_RESULTS_PERIODICITY_SEC = 3;
@@ -128,17 +125,21 @@ public class NetworkScanHelper {
private final TelephonyManager mTelephonyManager;
private final TelephonyScanManager.NetworkScanCallback mInternalNetworkScanCallback;
private final Executor mExecutor;
-
+ private final LegacyIncrementalScanBroadcastReceiver mLegacyIncrScanReceiver;
+ private Context mContext;
private NetworkScan mNetworkScanRequester;
+ private IntentFilter filter =
+ new IntentFilter("qualcomm.intent.action.ACTION_INCREMENTAL_NW_SCAN_IND");
- /** Callbacks for sync network scan */
- private ListenableFuture<List<CellInfo>> mNetworkScanFuture;
-
- public NetworkScanHelper(TelephonyManager tm, NetworkScanCallback callback, Executor executor) {
+ public NetworkScanHelper(Context context, TelephonyManager tm, NetworkScanCallback callback,
+ Executor executor) {
+ mContext = context;
mTelephonyManager = tm;
mNetworkScanCallback = callback;
mInternalNetworkScanCallback = new NetworkScanCallbackImpl();
mExecutor = executor;
+ mLegacyIncrScanReceiver =
+ new LegacyIncrementalScanBroadcastReceiver(mContext, mInternalNetworkScanCallback);
}
@VisibleForTesting
@@ -198,27 +199,8 @@ public class NetworkScanHelper {
* @param type used to tell which network scan API should be used.
*/
public void startNetworkScan(@NetworkQueryType int type) {
- if (type == NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS) {
- mNetworkScanFuture = SettableFuture.create();
- Futures.addCallback(mNetworkScanFuture, new FutureCallback<List<CellInfo>>() {
- @Override
- public void onSuccess(List<CellInfo> result) {
- onResults(result);
- onComplete();
- }
-
- @Override
- public void onFailure(Throwable t) {
- if (t instanceof CancellationException) {
- return;
- }
- int errCode = Integer.parseInt(t.getMessage());
- onError(errCode);
- }
- }, MoreExecutors.directExecutor());
- mExecutor.execute(new NetworkScanSyncTask(
- mTelephonyManager, (SettableFuture) mNetworkScanFuture));
- } else if (type == NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS) {
+ Log.d(TAG, "startNetworkScan: " + type);
+ if (type == NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS) {
if (mNetworkScanRequester != null) {
return;
}
@@ -230,6 +212,14 @@ public class NetworkScanHelper {
Log.d(TAG, "mNetworkScanRequester == null");
onError(NetworkScan.ERROR_RADIO_INTERFACE_ERROR);
}
+ } else if (type == NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS_LEGACY) {
+ mContext.registerReceiver(mLegacyIncrScanReceiver, filter);
+ boolean success = TelephonyUtils.performIncrementalScan(
+ mContext, mTelephonyManager.getSlotIndex());
+ Log.d(TAG, "success: " + success);
+ if (!success) {
+ onError(NetworkScan.ERROR_RADIO_INTERFACE_ERROR);
+ }
}
}
@@ -242,11 +232,20 @@ public class NetworkScanHelper {
if (mNetworkScanRequester != null) {
mNetworkScanRequester.stopScan();
mNetworkScanRequester = null;
- }
-
- if (mNetworkScanFuture != null) {
- mNetworkScanFuture.cancel(true /* mayInterruptIfRunning */);
- mNetworkScanFuture = null;
+ } else {
+ try {
+ int slotIndex = mTelephonyManager.getSlotIndex();
+ if (slotIndex >= 0 && slotIndex < mTelephonyManager.getActiveModemCount()) {
+ TelephonyUtils.abortIncrementalScan(mContext, slotIndex);
+ } else {
+ Log.d(TAG, "slotIndex is invalid, skipping abort");
+ }
+ mContext.unregisterReceiver(mLegacyIncrScanReceiver);
+ } catch (NullPointerException ex) {
+ Log.e(TAG, "abortIncrementalScan Exception: ", ex);
+ } catch (IllegalArgumentException ex) {
+ Log.e(TAG, "IllegalArgumentException");
+ }
}
}
@@ -268,23 +267,6 @@ public class NetworkScanHelper {
.anyMatch(i -> i == PhoneCapability.DEVICE_NR_CAPABILITY_SA);
}
- /**
- * Converts the status code of {@link CellNetworkScanResult} to one of the
- * {@link NetworkScan.ScanErrorCode}.
- * @param errCode status code from {@link CellNetworkScanResult}.
- *
- * @return one of the scan error code from {@link NetworkScan.ScanErrorCode}.
- */
- private static int convertToScanErrorCode(int errCode) {
- switch (errCode) {
- case CellNetworkScanResult.STATUS_RADIO_NOT_AVAILABLE:
- return NetworkScan.ERROR_RADIO_INTERFACE_ERROR;
- case CellNetworkScanResult.STATUS_RADIO_GENERIC_FAILURE:
- default:
- return NetworkScan.ERROR_MODEM_ERROR;
- }
- }
-
private final class NetworkScanCallbackImpl extends TelephonyScanManager.NetworkScanCallback {
public void onResults(List<CellInfo> results) {
Log.d(TAG, "Async scan onResults() results = "
@@ -302,35 +284,4 @@ public class NetworkScanHelper {
NetworkScanHelper.this.onError(errCode);
}
}
-
- private static final class NetworkScanSyncTask implements Runnable {
- private final SettableFuture<List<CellInfo>> mCallback;
- private final TelephonyManager mTelephonyManager;
-
- NetworkScanSyncTask(
- TelephonyManager telephonyManager, SettableFuture<List<CellInfo>> callback) {
- mTelephonyManager = telephonyManager;
- mCallback = callback;
- }
-
- @Override
- public void run() {
- final CellNetworkScanResult result = mTelephonyManager.getAvailableNetworks();
- if (result.getStatus() == CellNetworkScanResult.STATUS_SUCCESS) {
- final List<CellInfo> cellInfos = result.getOperators()
- .stream()
- .map(operatorInfo
- -> CellInfoUtil.convertOperatorInfoToCellInfo(operatorInfo))
- .collect(Collectors.toList());
- Log.d(TAG, "Sync network scan completed, cellInfos = "
- + CellInfoUtil.cellInfoListToString(cellInfos));
- mCallback.set(cellInfos);
- } else {
- final Throwable error = new Throwable(
- Integer.toString(convertToScanErrorCode(result.getStatus())));
- mCallback.setException(error);
- Log.d(TAG, "Sync network scan error, ex = " + error);
- }
- }
- }
}
diff --git a/src/com/android/settings/network/telephony/NetworkSelectSettings.java b/src/com/android/settings/network/telephony/NetworkSelectSettings.java
index 9faecbb180..6914ede4bc 100644
--- a/src/com/android/settings/network/telephony/NetworkSelectSettings.java
+++ b/src/com/android/settings/network/telephony/NetworkSelectSettings.java
@@ -29,6 +29,10 @@ import android.telephony.AccessNetworkConstants;
import android.telephony.CarrierConfigManager;
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
+import android.telephony.CellInfoCdma;
+import android.telephony.CellInfoGsm;
+import android.telephony.CellInfoLte;
+import android.telephony.CellInfoWcdma;
import android.telephony.NetworkRegistrationInfo;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
@@ -43,7 +47,10 @@ import androidx.preference.PreferenceCategory;
import com.android.internal.telephony.OperatorInfo;
import com.android.settings.R;
+import com.android.settings.Utils;
import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.network.SubscriptionUtil;
+import com.android.settings.network.SubscriptionsChangeListener;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.utils.ThreadUtils;
@@ -51,6 +58,8 @@ import com.android.settingslib.utils.ThreadUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -58,7 +67,8 @@ import java.util.concurrent.Executors;
/**
* "Choose network" settings UI for the Settings app.
*/
-public class NetworkSelectSettings extends DashboardFragment {
+public class NetworkSelectSettings extends DashboardFragment implements
+ SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
private static final String TAG = "NetworkSelectSettings";
@@ -81,12 +91,15 @@ public class NetworkSelectSettings extends DashboardFragment {
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@VisibleForTesting
TelephonyManager mTelephonyManager;
+ SubscriptionManager mSubscriptionManager;
+ private SubscriptionsChangeListener mSubscriptionsChangeListener;
private List<String> mForbiddenPlmns;
private boolean mShow4GForLTE = false;
private NetworkScanHelper mNetworkScanHelper;
private final ExecutorService mNetworkScanExecutor = Executors.newFixedThreadPool(1);
private MetricsFeatureProvider mMetricsFeatureProvider;
private boolean mUseNewApi;
+ private boolean mIsAdvancedScanSupported;
private long mRequestIdManualNetworkSelect;
private long mRequestIdManualNetworkScan;
private long mWaitingForNumberOfScanResults;
@@ -97,8 +110,13 @@ public class NetworkSelectSettings extends DashboardFragment {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mUseNewApi = getContext().getResources().getBoolean(
- com.android.internal.R.bool.config_enableNewAutoSelectNetworkUI);
+ if (TelephonyUtils.isServiceConnected()) {
+ mIsAdvancedScanSupported = TelephonyUtils.isAdvancedPlmnScanSupported(
+ getContext());
+ } else {
+ Log.d(TAG, "ExtTelephonyService is not connected!!! ");
+ }
+ Log.d(TAG, "mIsAdvancedScanSupported: " + mIsAdvancedScanSupported);
Intent intent = getActivity().getIntent();
if (intent != null) {
mSubId = intent.getIntExtra(Settings.EXTRA_SUB_ID,
@@ -111,8 +129,10 @@ public class NetworkSelectSettings extends DashboardFragment {
mSelectedPreference = null;
mTelephonyManager = getContext().getSystemService(TelephonyManager.class)
.createForSubscriptionId(mSubId);
+ mSubscriptionManager = getContext().getSystemService(SubscriptionManager.class);
+ mSubscriptionsChangeListener = new SubscriptionsChangeListener(getContext(), this);
mNetworkScanHelper = new NetworkScanHelper(
- mTelephonyManager, mCallback, mNetworkScanExecutor);
+ getContext(), mTelephonyManager, mCallback, mNetworkScanExecutor);
PersistableBundle bundle = ((CarrierConfigManager) getContext().getSystemService(
Context.CARRIER_CONFIG_SERVICE)).getConfigForSubId(mSubId);
if (bundle != null) {
@@ -138,18 +158,21 @@ public class NetworkSelectSettings extends DashboardFragment {
.findViewById(R.id.progress_bar_animation);
setProgressBarVisible(false);
}
- forceUpdateConnectedPreferenceCategory();
}
@Override
public void onStart() {
+ Log.d(TAG, "onStart()");
super.onStart();
+ mSubscriptionsChangeListener.start();
updateForbiddenPlmns();
if (isProgressBarVisible()) {
return;
}
if (mWaitingForNumberOfScanResults <= 0) {
+ // Clear the selected preference whenever the scan starts
+ mSelectedPreference = null;
startNetworkQuery();
}
}
@@ -167,6 +190,8 @@ public class NetworkSelectSettings extends DashboardFragment {
@Override
public void onStop() {
+ Log.d(TAG, "onStop() mWaitingForNumberOfScanResults: " + mWaitingForNumberOfScanResults);
+ mSubscriptionsChangeListener.stop();
super.onStop();
if (mWaitingForNumberOfScanResults <= 0) {
stopNetworkQuery();
@@ -211,6 +236,27 @@ public class NetworkSelectSettings extends DashboardFragment {
}
@Override
+ public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+ }
+
+ @Override
+ public void onSubscriptionsChanged() {
+ boolean isActiveSubscriptionId = mSubscriptionManager.isActiveSubscriptionId(mSubId);
+ Log.d(TAG, "onSubscriptionsChanged, mSubId: " + mSubId
+ + ", isActive: " + isActiveSubscriptionId);
+
+ if (!isActiveSubscriptionId) {
+ // The current subscription is no longer active, possibly because the SIM was removed.
+ // Finish the activity.
+ final Activity activity = getActivity();
+ if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
+ Log.d(TAG, "Calling finish");
+ activity.finish();
+ }
+ }
+ }
+
+ @Override
protected int getPreferenceScreenResId() {
return R.xml.choose_network;
}
@@ -228,10 +274,10 @@ public class NetworkSelectSettings extends DashboardFragment {
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
+ Log.d(TAG, "handleMessage, msg.what: " + msg.what);
switch (msg.what) {
case EVENT_SET_NETWORK_SELECTION_MANUALLY_DONE:
final boolean isSucceed = (boolean) msg.obj;
- stopNetworkQuery();
setProgressBarVisible(false);
getPreferenceScreen().setEnabled(true);
@@ -256,6 +302,7 @@ public class NetworkSelectSettings extends DashboardFragment {
}
mCellInfoList = doAggregation(results);
+ Log.d(TAG, "CellInfoList size: " + mCellInfoList.size());
Log.d(TAG, "CellInfoList: " + CellInfoUtil.cellInfoListToString(mCellInfoList));
if (mCellInfoList != null && mCellInfoList.size() != 0) {
final NetworkOperatorPreference connectedPref =
@@ -464,8 +511,22 @@ public class NetworkSelectSettings extends DashboardFragment {
if (mForbiddenPlmns == null) {
updateForbiddenPlmns();
}
+
+ Set<CellIdentity> cellIdentitySet = new HashSet<CellIdentity>();
for (NetworkRegistrationInfo regInfo : networkList) {
+ Log.d(TAG, "regInfo: " + regInfo.toString());
+ // There can be multiple NetworkRegistrationInfos for the same CellIdentity,
+ // e.g., one each for CS and PS. In such cases, show show only one entry,
+ // otherwise it would be quite confusing to the user to see multiple entries for
+ // the same CellIdentity instance.
final CellIdentity cellIdentity = regInfo.getCellIdentity();
+ if (cellIdentity != null) {
+ // Add each valid CellIdentity to a HashSet so that only unique values remain.
+ cellIdentitySet.add(cellIdentity);
+ }
+ }
+
+ for (CellIdentity cellIdentity : cellIdentitySet) {
if (cellIdentity == null) {
continue;
}
@@ -480,7 +541,6 @@ public class NetworkSelectSettings extends DashboardFragment {
// (it would be quite confusing why the connected network has no signal)
pref.setIcon(SignalStrength.NUM_SIGNAL_STRENGTH_BINS - 1);
mPreferenceCategory.addPreference(pref);
- break;
}
}
}
@@ -528,10 +588,11 @@ public class NetworkSelectSettings extends DashboardFragment {
if (mNetworkScanHelper != null) {
mRequestIdManualNetworkScan = getNewRequestId();
mWaitingForNumberOfScanResults = MIN_NUMBER_OF_SCAN_REQUIRED;
+
mNetworkScanHelper.startNetworkScan(
- mUseNewApi
+ mIsAdvancedScanSupported
? NetworkScanHelper.NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS
- : NetworkScanHelper.NETWORK_SCAN_TYPE_WAIT_FOR_ALL_RESULTS);
+ : NetworkScanHelper.NETWORK_SCAN_TYPE_INCREMENTAL_RESULTS_LEGACY);
}
}
@@ -545,6 +606,7 @@ public class NetworkSelectSettings extends DashboardFragment {
@Override
public void onDestroy() {
+ Log.d(TAG, "onDestroy()");
stopNetworkQuery();
mNetworkScanExecutor.shutdown();
super.onDestroy();
diff --git a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java
index 24197795fa..31b9de524b 100644..100755
--- a/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java
+++ b/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceController.java
@@ -16,28 +16,49 @@
package com.android.settings.network.telephony;
+import static androidx.lifecycle.Lifecycle.Event.ON_START;
+import static androidx.lifecycle.Lifecycle.Event.ON_STOP;
+
import android.content.Context;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.os.Looper;
import android.os.PersistableBundle;
+import android.provider.Settings;
import android.telephony.CarrierConfigManager;
+import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.util.Log;
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
import com.android.settings.R;
+import com.android.settings.network.AllowedNetworkTypesListener;
import com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants;
/**
* Preference controller for "Preferred network mode"
*/
public class PreferredNetworkModePreferenceController extends TelephonyBasePreferenceController
- implements ListPreference.OnPreferenceChangeListener {
+ implements ListPreference.OnPreferenceChangeListener, LifecycleObserver {
+ private static final String LOG_TAG = "PreferredNetworkMode";
private CarrierConfigManager mCarrierConfigManager;
private TelephonyManager mTelephonyManager;
private PersistableBundle mPersistableBundle;
private boolean mIsGlobalCdma;
+ private Preference mPreference;
+ private PhoneCallStateListener mPhoneStateListener;
+ private AllowedNetworkTypesListener mAllowedNetworkTypesListener;
+ @VisibleForTesting
+ Integer mCallState;
public PreferredNetworkModePreferenceController(Context context, String key) {
super(context, key);
@@ -66,6 +87,33 @@ public class PreferredNetworkModePreferenceController extends TelephonyBasePrefe
return visible ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
+ @OnLifecycleEvent(ON_START)
+ public void onStart() {
+ if (mPhoneStateListener != null) {
+ mPhoneStateListener.register(mContext, mSubId);
+ }
+ if (mAllowedNetworkTypesListener != null) {
+ mAllowedNetworkTypesListener.register(mContext, mSubId);
+ }
+
+ }
+
+ @OnLifecycleEvent(ON_STOP)
+ public void onStop() {
+ if (mPhoneStateListener != null) {
+ mPhoneStateListener.unregister();
+ }
+ if (mAllowedNetworkTypesListener != null) {
+ mAllowedNetworkTypesListener.unregister(mContext, mSubId);
+ }
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mPreference = screen.findPreference(getPreferenceKey());
+ }
+
@Override
public void updateState(Preference preference) {
super.updateState(preference);
@@ -73,6 +121,7 @@ public class PreferredNetworkModePreferenceController extends TelephonyBasePrefe
final int networkMode = getPreferredNetworkMode();
listPreference.setValue(Integer.toString(networkMode));
listPreference.setSummary(getPreferredNetworkModeSummaryResId(networkMode));
+ listPreference.setEnabled(isCallStateIdle());
}
@Override
@@ -83,19 +132,37 @@ public class PreferredNetworkModePreferenceController extends TelephonyBasePrefe
TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER,
MobileNetworkUtils.getRafFromNetworkType(newPreferredNetworkMode));
- final ListPreference listPreference = (ListPreference) preference;
- listPreference.setSummary(getPreferredNetworkModeSummaryResId(newPreferredNetworkMode));
- return true;
+ final ListPreference listPreference = (ListPreference) preference;
+ listPreference.setSummary(getPreferredNetworkModeSummaryResId(newPreferredNetworkMode));
+ return true;
}
- public void init(int subId) {
+ public void init(Lifecycle lifecycle, int subId) {
mSubId = subId;
+ if (mPhoneStateListener == null) {
+ mPhoneStateListener = new PhoneCallStateListener();
+ }
final PersistableBundle carrierConfig = mCarrierConfigManager.getConfigForSubId(mSubId);
mTelephonyManager = mContext.getSystemService(TelephonyManager.class)
.createForSubscriptionId(mSubId);
mIsGlobalCdma = mTelephonyManager.isLteCdmaEvdoGsmWcdmaEnabled()
&& carrierConfig.getBoolean(CarrierConfigManager.KEY_SHOW_CDMA_CHOICES_BOOL);
+
+ if (mAllowedNetworkTypesListener == null) {
+ mAllowedNetworkTypesListener = new AllowedNetworkTypesListener(
+ mContext.getMainExecutor());
+ mAllowedNetworkTypesListener.setAllowedNetworkTypesListener(
+ () -> updatePreference());
+ }
+
+ lifecycle.addObserver(this);
+ }
+
+ private void updatePreference() {
+ if (mPreference != null) {
+ updateState(mPreference);
+ }
}
private int getPreferredNetworkMode() {
@@ -186,4 +253,42 @@ public class PreferredNetworkModePreferenceController extends TelephonyBasePrefe
return R.string.preferred_network_mode_global_summary;
}
}
+
+ private boolean isCallStateIdle() {
+ boolean callStateIdle = true;
+ if (mCallState != null && mCallState != TelephonyManager.CALL_STATE_IDLE) {
+ callStateIdle = false;
+ }
+ Log.d(LOG_TAG, "isCallStateIdle:" + callStateIdle);
+ return callStateIdle;
+ }
+
+ private class PhoneCallStateListener extends PhoneStateListener {
+
+ PhoneCallStateListener() {
+ super(Looper.getMainLooper());
+ }
+
+ private TelephonyManager mTelephonyManager;
+
+ @Override
+ public void onCallStateChanged(int state, String incomingNumber) {
+ mCallState = state;
+ updateState(mPreference);
+ }
+
+ public void register(Context context, int subId) {
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
+ }
+ mTelephonyManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE);
+
+ }
+
+ public void unregister() {
+ mCallState = null;
+ mTelephonyManager.listen(this, PhoneStateListener.LISTEN_NONE);
+ }
+ }
}
diff --git a/src/com/android/settings/network/telephony/TelephonyUtils.java b/src/com/android/settings/network/telephony/TelephonyUtils.java
new file mode 100644
index 0000000000..a759972b55
--- /dev/null
+++ b/src/com/android/settings/network/telephony/TelephonyUtils.java
@@ -0,0 +1,227 @@
+/**
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.android.settings.network.telephony;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.qti.extphone.ExtTelephonyManager;
+import com.qti.extphone.QtiImeiInfo;
+import com.qti.extphone.ServiceCallback;
+
+import org.codeaurora.internal.IExtTelephony;
+import java.util.Optional;
+
+/**
+ * Add static utility functions to get information about Primary Card and Subsidy Lock features.
+ */
+public final class TelephonyUtils {
+
+ private static final String TAG = "TelephonyUtils";
+
+ // Flag to control debug logging for primary card and subsidy lock features
+ public static boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+
+ private static final String PROPERTY_ADVANCED_SCAN = "persist.vendor.radio.enableadvancedscan";
+
+ private static final String PROPERTY_SUBSIDY_DEVICE = "persist.vendor.radio.subsidydevice";
+ private static final String ALLOW_USER_SELECT_DDS = "allow_user_select_dds";
+
+ // Modem version prefix tag
+ private static final String MODEM_VERSION_PREFIX_HI_TAG = "MPSS.HI."; // Himalaya
+ private static final String MODEM_VERSION_PREFIX_DE_TAG = "MPSS.DE."; // Denali
+
+ // UICC provisioning status
+ public static final int CARD_NOT_PROVISIONED = 0;
+ public static final int CARD_PROVISIONED = 1;
+ public static final int CARD_INVALID_STATE = -1;
+
+ private static ExtTelephonyManager mExtTelephonyManager;
+ private static boolean mIsServiceBound;
+ private static Optional<Boolean> mIsSubsidyFeatureEnabled = Optional.empty();
+
+ private TelephonyUtils() {
+ }
+
+ public static boolean isAdvancedPlmnScanSupported(Context context) {
+ boolean propVal = false;
+ if (mIsServiceBound) {
+ try {
+ propVal = mExtTelephonyManager.getPropertyValueBool(PROPERTY_ADVANCED_SCAN, false);
+ } catch (NullPointerException ex) {
+ Log.e(TAG, "isAdvancedPlmnScanSupported: , Exception: ", ex);
+ }
+ } else {
+ Log.e(TAG, "isAdvancedPlmnScanSupported: ExtTelephony Service not connected!");
+ }
+ return propVal;
+ }
+
+ public static boolean performIncrementalScan(Context context, int slotId) {
+ boolean success = false;
+ if (mIsServiceBound) {
+ success = mExtTelephonyManager.performIncrementalScan(slotId);
+ } else {
+ Log.e(TAG, "performIncrementalScan: ExtTelephony Service not connected!");
+ }
+ return success;
+ }
+
+ public static void abortIncrementalScan(Context context, int slotId) {
+ if (mIsServiceBound) {
+ mExtTelephonyManager.abortIncrementalScan(slotId);
+ } else {
+ Log.e(TAG, "abortIncrementalScan: ExtTelephony Service not connected!");
+ }
+ }
+
+ /*
+ * As many products come from different modem version, it is hard to maintain one
+ * carrier config along with vendor product SKU. But MPSS version code is stable
+ * very much, it is a good way rather than config's approach.
+ */
+ public static boolean isDual5gSupported(TelephonyManager telephonyManager) {
+ if (telephonyManager == null) {
+ Log.e(TAG, "telephonyManager is null");
+ return false;
+ }
+ final String version = telephonyManager.getBasebandVersion();
+ Log.d(TAG, "Base band version = " + version);
+ if (!TextUtils.isEmpty(version)) {
+ String[] tokens = version.split("-");
+ if (tokens != null) {
+ for (String token : tokens) {
+ if (token != null && token.startsWith(MODEM_VERSION_PREFIX_HI_TAG)) {
+ String verCode =
+ token.substring(MODEM_VERSION_PREFIX_HI_TAG.length(),
+ token.length());
+ Log.d(TAG, "verCode = " + verCode);
+ if (verCode != null && verCode.length() > 2) {
+ String[] subCode = verCode.split("\\.");
+ try {
+ int major = Integer.parseInt(subCode[0]);
+ int minor = Integer.parseInt(subCode[1]);
+ Log.d(TAG, "Ver major = " + major + " minor = " + minor);
+ if (major >= 4 && minor >= 3) {
+ return true;
+ }
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "Fail to parse version");
+ return false;
+ }
+ }
+ } else if (token != null && token.startsWith(MODEM_VERSION_PREFIX_DE_TAG)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public static boolean isSubsidyFeatureEnabled(Context context) {
+ if (!mIsSubsidyFeatureEnabled.isPresent()) {
+ if (!mIsServiceBound) {
+ Log.e(TAG, "isSubsidyFeatureEnabled: ExtTelephony Service not connected!");
+ connectExtTelephonyService(context);
+ }
+
+ try {
+ mIsSubsidyFeatureEnabled =
+ Optional.of(mExtTelephonyManager.getPropertyValueBool(
+ PROPERTY_SUBSIDY_DEVICE, false));
+ } catch (NullPointerException ex) {
+ Log.e(TAG, "isSubsidyFeatureEnabled: , Exception: ", ex);
+ }
+ }
+ return mIsSubsidyFeatureEnabled.get();
+ }
+
+ public static boolean allowUsertoSetDDS(Context context) {
+ return Settings.Global.getInt(context.getContentResolver(), ALLOW_USER_SELECT_DDS, 0) == 1;
+ }
+
+ public static boolean isSubsidySimCard(Context context, int slotId) {
+ boolean isSubsidySim = false;
+ if (!mIsServiceBound) {
+ Log.e(TAG, "isSubsidySimCard: ExtTelephony Service not connected!");
+ connectExtTelephonyService(context);
+ }
+
+ try {
+ isSubsidySim = mExtTelephonyManager.isPrimaryCarrierSlotId(slotId);
+ } catch (NullPointerException ex) {
+ Log.e(TAG, "isSubsidySimCard: , Exception: ", ex);
+ }
+ return isSubsidySim;
+ }
+
+ public static QtiImeiInfo[] getImeiInfo() {
+ QtiImeiInfo[] qtiImeiInfo = null;
+ if (isServiceConnected()) {
+ qtiImeiInfo = mExtTelephonyManager.getImeiInfo();
+ } else {
+ Log.e(TAG, "getImeiInfo: ExtTelephony Service not connected!");
+ }
+ return qtiImeiInfo;
+ }
+
+ public static void connectExtTelephonyService(Context context) {
+ if (!mIsServiceBound) {
+ Log.d(TAG, "Connect to ExtTelephonyService...");
+ mExtTelephonyManager = ExtTelephonyManager.getInstance(context);
+ mExtTelephonyManager.connectService(mServiceCallback);
+ }
+ }
+
+ public static boolean isServiceConnected() {
+ return mIsServiceBound;
+ }
+
+ private static ServiceCallback mServiceCallback = new ServiceCallback() {
+ @Override
+ public void onConnected() {
+ Log.d(TAG, "ExtTelephony Service connected");
+ mIsServiceBound = true;
+ }
+
+ @Override
+ public void onDisconnected() {
+ Log.d(TAG, "ExtTelephony Service disconnected...");
+ mIsServiceBound = false;
+ }
+ };
+}
diff --git a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
index 0064e6ccfd..7baadd3a8e 100644
--- a/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
+++ b/src/com/android/settings/network/telephony/ToggleSubscriptionDialogActivity.java
@@ -292,7 +292,7 @@ public class ToggleSubscriptionDialogActivity extends SubscriptionActionDialogAc
}
private void handleTogglePsimAction() {
- if (mSubscriptionManager.canDisablePhysicalSubscription() && mSubInfo != null) {
+ if (mSubInfo != null) {
mSubscriptionManager.setUiccApplicationsEnabled(mSubInfo.getSubscriptionId(), mEnable);
finish();
} else {
diff --git a/src/com/android/settings/network/telephony/UserPLMNEditorActivity.java b/src/com/android/settings/network/telephony/UserPLMNEditorActivity.java
new file mode 100755
index 0000000000..dfac3fa180
--- /dev/null
+++ b/src/com/android/settings/network/telephony/UserPLMNEditorActivity.java
@@ -0,0 +1,406 @@
+/**
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.android.settings.network.telephony;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.text.InputType;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.preference.EditTextPreference;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.provider.Settings;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.settings.R;
+
+import java.util.List;
+
+/**
+ * Editor activity for "User Controlled PLMN"
+ */
+public class UserPLMNEditorActivity extends PreferenceActivity implements
+ Preference.OnPreferenceChangeListener, TextWatcher {
+ private static final String LOG_TAG = "UserPLMNEditorActivity";
+ private static final int MENU_DELETE_OPTION = Menu.FIRST;
+ private static final int MENU_SAVE_OPTION = Menu.FIRST + 1;
+ private static final int MENU_CANCEL_OPTION = Menu.FIRST + 2;
+ private static final int NWID_DIALOG_ID = 0;
+
+ private static final String BUTTON_NETWORK_ID_KEY = "network_id_key";
+ private static final String BUTTON_PRIORITY_KEY = "priority_key";
+ private static final String BUTTON_NEWWORK_MODE_KEY = "network_mode_key";
+
+ public static final String UPLMN_CODE = "uplmn_code";
+ public static final String UPLMN_PRIORITY = "uplmn_priority";
+ public static final String UPLMN_SERVICE = "uplmn_service";
+ public static final String UPLMN_SIZE = "uplmn_size";
+ public static final String UPLMN_ADD = "uplmn_add";
+
+ public static final int RESULT_CODE_EDIT = 101;
+ public static final int RESULT_CODE_DELETE = 102;
+
+ private static final int GSM = 0;
+ private static final int WCDMA_TDSCDMA = 1;
+ private static final int LTE = 2;
+ private static final int TRIPLE_MODE = 3;
+ private static final int MODE_2G = 0x1;
+ private static final int MODE_3G = 0x4;
+ private static final int MODE_LTE = 0x8;
+ private static final int MODE_TRIPLE = 0xd;
+
+ private String mNoSet = null;
+ private boolean mAirplaneModeOn = false;
+ private IntentFilter mIntentFilter;
+ private Preference mNWIDPref = null;
+ private EditTextPreference mPRIpref = null;
+ private ListPreference mNWMPref = null;
+ private EditText mNWIDText;
+ private AlertDialog mNWIDDialog = null;
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
+ mAirplaneModeOn = intent.getBooleanExtra("state", false);
+ setScreenEnabled();
+ }
+ }
+ };
+
+ private OnClickListener mNWIDPrefListener = new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == DialogInterface.BUTTON_POSITIVE) {
+ String summary = genText(mNWIDText.getText().toString());
+ Log.d(LOG_TAG, "input network id is " + summary);
+ mNWIDPref.setSummary(summary);
+ mNWMPref.setEntries(getResources().getTextArray(
+ selectNetworkChoices(summary)));
+ }
+ }
+ };
+
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ addPreferencesFromResource(R.xml.uplmn_editor);
+ mNoSet = getResources().getString(R.string.voicemail_number_not_set);
+
+ mNWIDPref = (Preference) findPreference(BUTTON_NETWORK_ID_KEY);
+ mPRIpref = (EditTextPreference) findPreference(BUTTON_PRIORITY_KEY);
+ mNWMPref = (ListPreference) findPreference(BUTTON_NEWWORK_MODE_KEY);
+
+ mPRIpref.setOnPreferenceChangeListener(this);
+ mNWMPref.setOnPreferenceChangeListener(this);
+
+ mIntentFilter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ registerReceiver(mReceiver, mIntentFilter);
+ }
+
+ protected void onResume() {
+ super.onResume();
+ displayNetworkInfo(getIntent());
+ mAirplaneModeOn =
+ Settings.System.getInt(
+ getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+ setScreenEnabled();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mReceiver);
+ }
+
+ public boolean onPreferenceChange(Preference preference, Object object) {
+ String value = object.toString();
+ if (preference == mPRIpref) {
+ mPRIpref.setSummary(genText(value));
+ } else if (preference == mNWMPref) {
+ mNWMPref.setValue(value);
+ String summary = "";
+ int index = Integer.parseInt(value);
+ summary = getResources().getStringArray(
+ selectNetworkChoices(mNWIDPref.getSummary().toString()))[index];
+ mNWMPref.setSummary(summary);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ if (!getIntent().getBooleanExtra(UPLMN_ADD, false)) {
+ menu.add(0, MENU_DELETE_OPTION, 0,
+ com.android.internal.R.string.delete);
+ }
+ menu.add(0, MENU_SAVE_OPTION, 0, R.string.save);
+ menu.add(0, MENU_CANCEL_OPTION, 0, com.android.internal.R.string.cancel);
+ return true;
+ }
+
+ @Override
+ public boolean onMenuOpened(int featureId, Menu menu) {
+ super.onMenuOpened(featureId, menu);
+ boolean isEmpty = mNoSet.equals(mNWIDPref.getSummary())
+ || mNoSet.equals(mPRIpref.getSummary());
+ if (menu != null) {
+ menu.setGroupEnabled(0, !mAirplaneModeOn);
+ //only show the save and delete option menu when radio on
+ //and edit text is not empty.
+ if (getIntent().getBooleanExtra(UPLMN_ADD, true)) {
+ menu.getItem(0).setEnabled((!mAirplaneModeOn) && !isEmpty);
+ } else {
+ menu.getItem(1).setEnabled((!mAirplaneModeOn) && !isEmpty);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_SAVE_OPTION:
+ setSavedNWInfo();
+ break;
+ case MENU_DELETE_OPTION:
+ setRemovedNWInfo();
+ break;
+ case MENU_CANCEL_OPTION:
+ break;
+ case android.R.id.home:
+ finish();
+ return true;
+ default:
+ break;
+ }
+ finish();
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void setSavedNWInfo() {
+ Intent intent = new Intent(this, UserPLMNListActivity.class);
+ genNWInfoToIntent(intent);
+ setResult(RESULT_CODE_EDIT, intent);
+ }
+
+ private void genNWInfoToIntent(Intent intent) {
+ int priority = 0;
+ int plmnListSize = getIntent().getIntExtra(UPLMN_SIZE, 0);
+ try {
+ priority = Integer.parseInt(String.valueOf(mPRIpref.getSummary()));
+ } catch (NumberFormatException e) {
+ Log.d(LOG_TAG, "parse value of basband error");
+ }
+ if (getIntent().getBooleanExtra(UPLMN_ADD, false)) {
+ if (priority > plmnListSize) {
+ priority = plmnListSize;
+ }
+ } else {
+ if (priority >= plmnListSize) {
+ priority = plmnListSize - 1;
+ }
+ }
+ intent.putExtra(UPLMN_PRIORITY, priority);
+
+ try {
+ intent.putExtra(UPLMN_SERVICE, convertApMode2EF(Integer
+ .parseInt(String.valueOf(mNWMPref.getValue()))));
+ } catch (NumberFormatException e) {
+ intent.putExtra(UPLMN_SERVICE, convertApMode2EF(0));
+ }
+
+ intent.putExtra(UPLMN_CODE, mNWIDPref.getSummary());
+ }
+
+ private void setRemovedNWInfo() {
+ Intent intent = new Intent(this, UserPLMNListActivity.class);
+ genNWInfoToIntent(intent);
+ setResult(RESULT_CODE_DELETE, intent);
+ }
+
+ public static int convertEFMode2Ap(int mode) {
+ int result = 0;
+ if (mode == MODE_TRIPLE) {
+ result = TRIPLE_MODE;
+ } else if (mode == MODE_3G) {
+ result = WCDMA_TDSCDMA;
+ } else if (mode == MODE_LTE) {
+ result = LTE;
+ } else {
+ result = GSM;
+ }
+ return result;
+ }
+
+ public static int convertApMode2EF(int mode) {
+ int result = 0;
+ if (mode == TRIPLE_MODE) {
+ result = MODE_TRIPLE;
+ } else if (mode == LTE) {
+ result = MODE_LTE;
+ } else if (mode == WCDMA_TDSCDMA) {
+ result = MODE_3G;
+ } else {
+ result = MODE_2G;
+ }
+ return result;
+ }
+
+ private void displayNetworkInfo(Intent intent) {
+ String number = intent.getStringExtra(UPLMN_CODE);
+ mNWIDPref.setSummary(genText(number));
+ int priority = intent.getIntExtra(UPLMN_PRIORITY, 0);
+ mPRIpref.setSummary(String.valueOf(priority));
+ mPRIpref.setText(String.valueOf(priority));
+ int act = intent.getIntExtra(UPLMN_SERVICE, 0);
+
+ Log.d(LOG_TAG, "act = " + act);
+
+ act = convertEFMode2Ap(act);
+ if (act < GSM || act > TRIPLE_MODE) {
+ act = GSM;
+ }
+ String summary = "";
+ mNWMPref.setEntries(getResources().getTextArray(
+ selectNetworkChoices(number)));
+ summary = getResources().getStringArray(
+ selectNetworkChoices(number))[act];
+ mNWMPref.setSummary(summary);
+ mNWMPref.setValue(String.valueOf(act));
+ }
+
+ public int selectNetworkChoices(String plmn) {
+ Log.d(LOG_TAG, "plmn = " + plmn);
+ String[] CuPlmnArray = getResources().getStringArray(R.array.uplmn_cu_mcc_mnc_values);
+ for (String CuPlmn : CuPlmnArray) {
+ if (!TextUtils.isEmpty(plmn) && plmn.equals(CuPlmn)) {
+ return R.array.uplmn_prefer_network_mode_w_choices;
+ }
+ }
+ return R.array.uplmn_prefer_network_mode_td_choices;
+ }
+
+ private String genText(String value) {
+ if (value == null || value.length() == 0) {
+ return mNoSet;
+ } else {
+ return value;
+ }
+ }
+
+ public void buttonEnabled() {
+ int len = mNWIDText.getText().toString().length();
+ boolean state = true;
+ if (len <5 || len > 6) {
+ state = false;
+ }
+ if (mNWIDDialog != null) {
+ mNWIDDialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(
+ state);
+ }
+ }
+
+ private void setScreenEnabled() {
+ getPreferenceScreen().setEnabled(!mAirplaneModeOn);
+ invalidateOptionsMenu();
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen screen,
+ Preference preference) {
+ if (preference == mNWIDPref) {
+ removeDialog(NWID_DIALOG_ID);
+ showDialog(NWID_DIALOG_ID);
+ buttonEnabled();
+ }
+ return super.onPreferenceTreeClick(screen, preference);
+ }
+
+ @Override
+ public Dialog onCreateDialog(int id) {
+ if (id == NWID_DIALOG_ID) {
+ mNWIDText = new EditText(this);
+ if (!mNoSet.equals(mNWIDPref.getSummary())) {
+ mNWIDText.setText(mNWIDPref.getSummary());
+ }
+ mNWIDText.addTextChangedListener(this);
+ mNWIDText.setInputType(InputType.TYPE_CLASS_NUMBER);
+ mNWIDDialog = new AlertDialog.Builder(this)
+ .setTitle(getResources().getString(R.string.network_id))
+ .setView(mNWIDText)
+ .setPositiveButton(
+ getResources().getString(
+ com.android.internal.R.string.ok),
+ mNWIDPrefListener)
+ .setNegativeButton(
+ getResources().getString(
+ com.android.internal.R.string.cancel), null)
+ .create();
+ mNWIDDialog.getWindow().setSoftInputMode(
+ WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+ return mNWIDDialog;
+ }
+ return null;
+ }
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count,
+ int after) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ buttonEnabled();
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+}
diff --git a/src/com/android/settings/network/telephony/UserPLMNListActivity.java b/src/com/android/settings/network/telephony/UserPLMNListActivity.java
new file mode 100755
index 0000000000..a49ce87e43
--- /dev/null
+++ b/src/com/android/settings/network/telephony/UserPLMNListActivity.java
@@ -0,0 +1,748 @@
+/**
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.android.settings.network.telephony;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.AsyncResult;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.provider.Settings;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
+import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.util.Log;
+
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.telephony.uicc.IccConstants;
+import com.android.internal.telephony.uicc.IccUtils;
+import com.android.internal.telephony.uicc.PlmnActRecord;
+import com.android.internal.telephony.uicc.UiccController;
+import com.android.settings.R;
+
+import org.codeaurora.internal.IExtTelephony;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * List the MCCMNC and the priority for "User Controlled PLMN"
+ */
+public class UserPLMNListActivity extends PreferenceActivity
+ implements DialogInterface.OnCancelListener {
+ private static final String LOG_TAG = "UserPLMNListActivity";
+ private static final boolean DBG = true;
+
+ private static final int BUSY_READING_DIALOG = 99;
+ private static final int BUSY_SAVING_DIALOG = 100;
+ private static final int UPLMNLIST_ADD = 101;
+ private static final int UPLMNLIST_EDIT = 102;
+ private static final int MENU_ADD_OPTIION = Menu.FIRST;
+
+ /* 5n bytes:
+ 1 to 3 nth PLMN (highest priority)
+ 4 to 5 nth PLMN Access Technology Identifier */
+ private static final int UPLMN_SEL_DATA_LEN = 5;
+ private static final int GSM_MASK = 1;
+ /**
+ * GSM compact access technology.
+ */
+ private static final int GSM_COMPACT_MASK = 2;
+ /**
+ * UMTS radio access technology.
+ */
+ private static final int UMTS_MASK = 4;
+ /**
+ * LTE radio access technology.
+ */
+ private static final int LTE_MASK = 8;
+
+ private List<UPLMNInfoWithEf> mUPLMNList;
+ private PreferenceScreen mUPLMNListContainer;
+ private static final String BUTTON_UPLMN_LIST_KEY = "button_uplmn_list_key";
+ private Map<Preference, UPLMNInfoWithEf> mPreferenceMap
+ = new LinkedHashMap<Preference, UPLMNInfoWithEf>();
+ private UPLMNInfoWithEf mOldInfo;
+ private int mNumRec = 0;
+ private boolean mAirplaneModeOn = false;
+ private int mPhoneId = 0;
+ protected boolean mIsForeground = false;
+
+ private MyHandler mHandler = new MyHandler();
+ private IExtTelephony mExtTelephony;
+ private static final String ACTION_READ_EF_BROADCAST =
+ "com.qualcomm.qti.intent.action.ACTION_READ_EF_RESULT";
+ private static final String ACTION_WRITE_EF_BROADCAST =
+ "com.qualcomm.qti.intent.action.ACTION_WRITE_EF_RESULT";
+
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
+ mAirplaneModeOn = intent.getBooleanExtra("state", false);
+ setScreenEnabled();
+ } else if (ACTION_READ_EF_BROADCAST.equals(action)) {
+ if (intent.getBooleanExtra("exception", false)) {
+ log("ACTION_READ_EF_BROADCAST with exception");
+ Message message = mHandler.obtainMessage();
+ message.what = mHandler.MESSAGE_GET_UPLMN_LIST;
+ message.obj = new AsyncResult(null, null, new Exception());
+ // trigger tone stop after timeout duration
+ mHandler.sendMessage(message);
+ } else {
+ handleGetEFDone(intent.getByteArrayExtra("payload"));
+ }
+ } else if (ACTION_WRITE_EF_BROADCAST.equals(action)) {
+ if (intent.getBooleanExtra("exception", false)) {
+ log("ACTION_WRITE_EF_BROADCAST with exception");
+ } else {
+ log("handleSetEFDone: with OK result!");
+ }
+ getUPLMNInfoFromEf();
+ }
+ }
+ };
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ ProgressDialog dialog = new ProgressDialog(this);
+ dialog.setTitle(getText(R.string.uplmn_settings_title));
+ dialog.setIndeterminate(true);
+ switch(id) {
+ case BUSY_READING_DIALOG:
+ dialog.setCancelable(true);
+ dialog.setOnCancelListener(this);
+ dialog.setMessage(getText(R.string.reading_settings));
+ return dialog;
+ case BUSY_SAVING_DIALOG:
+ dialog.setCancelable(false);
+ dialog.setMessage(getText(R.string.updating_settings));
+ return dialog;
+ }
+ return null;
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ finish();
+ }
+
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ addPreferencesFromResource(R.xml.uplmn_settings);
+ mUPLMNListContainer = (PreferenceScreen) findPreference(BUTTON_UPLMN_LIST_KEY);
+ int subId = getIntent().getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ mPhoneId = SubscriptionManager.getPhoneId(subId);
+
+ mExtTelephony
+ = IExtTelephony.Stub
+ .asInterface(ServiceManager.getService("qti.radio.extphone"));
+
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ intentFilter.addAction(ACTION_WRITE_EF_BROADCAST);
+ intentFilter.addAction(ACTION_READ_EF_BROADCAST);
+ registerReceiver(mReceiver, intentFilter);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ unregisterReceiver(mReceiver);
+ }
+
+ public void onResume() {
+ super.onResume();
+ mIsForeground = true;
+ getUPLMNInfoFromEf();
+ showReadingDialog();
+ mAirplaneModeOn = Settings.System.getInt(getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mIsForeground = false;
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ menu.add(0, MENU_ADD_OPTIION, 0, R.string.uplmn_list_setting_add_plmn)
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ if (menu != null) {
+ menu.setGroupEnabled(0, !mAirplaneModeOn);
+ }
+ return super.onPrepareOptionsMenu(menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_ADD_OPTIION:
+ if (!hasGetIccFileHandler()) return true;
+ Intent intent = new Intent(this, UserPLMNEditorActivity.class);
+ intent.putExtra(UserPLMNEditorActivity.UPLMN_CODE, "");
+ intent.putExtra(UserPLMNEditorActivity.UPLMN_PRIORITY, 0);
+ intent.putExtra(UserPLMNEditorActivity.UPLMN_SERVICE, 0);
+ intent.putExtra(UserPLMNEditorActivity.UPLMN_ADD, true);
+ intent.putExtra(UserPLMNEditorActivity.UPLMN_SIZE, mUPLMNList.size());
+ startActivityForResult(intent, UPLMNLIST_ADD);
+ break;
+ case android.R.id.home:
+ finish();
+ return true;
+ default:
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ private void showReadingDialog() {
+ if (mIsForeground && hasGetIccFileHandler()) {
+ showDialog(BUSY_READING_DIALOG);
+ }
+ }
+
+ private void showSavingDialog() {
+ if (mIsForeground) {
+ showDialog(BUSY_SAVING_DIALOG);
+ }
+ }
+
+ private void dismissDialogSafely(int id) {
+ try {
+ dismissDialog(id);
+ } catch (IllegalArgumentException e) {
+ // This is expected in the case where we were in the background
+ // at the time we would normally have shown the dialog, so we didn't
+ // show it.
+ }
+ }
+
+ public void onFinished(Preference preference, boolean reading) {
+ log("onFinished reading: " + reading);
+ if (reading) {
+ dismissDialogSafely(BUSY_READING_DIALOG);
+ } else {
+ dismissDialogSafely(BUSY_SAVING_DIALOG);
+ }
+ preference.setEnabled(true);
+ setScreenEnabled();
+ }
+
+ private void getUPLMNInfoFromEf() {
+ log("UPLMNInfoFromEf Start read...");
+ if (!readEfFromIcc(IccConstants.EF_PLMN_W_ACT)) {
+ Log.w(LOG_TAG, "mIccFileHandler is null");
+ }
+ }
+
+ private boolean hasGetIccFileHandler() {
+ boolean success = false;
+ try {
+ if (mExtTelephony != null) {
+ success = mExtTelephony.hasGetIccFileHandler(mPhoneId, UiccController.APP_FAM_3GPP);
+ }
+ } catch (RemoteException | NullPointerException ex) {
+ Log.e(LOG_TAG, "hasGetIccFileHandler Exception: ", ex);
+
+ }
+ return success;
+ }
+
+ private boolean readEfFromIcc(int efid) {
+ boolean success = false;
+ try {
+ if (mExtTelephony != null) {
+ success = mExtTelephony.readEfFromIcc(mPhoneId, UiccController.APP_FAM_3GPP, efid);
+ }
+ } catch (RemoteException | NullPointerException ex) {
+ Log.e(LOG_TAG, "readEfFromIcc Exception: ", ex);
+
+ }
+ return success;
+ }
+
+ private boolean writeEfToIcc(byte[] efdata, int efid) {
+ boolean success = false;
+ try {
+ if (mExtTelephony != null) {
+ success = mExtTelephony.writeEfToIcc(mPhoneId, UiccController.APP_FAM_3GPP,
+ efid, efdata);
+ }
+ } catch (RemoteException | NullPointerException ex) {
+ Log.e(LOG_TAG, "writeEfToIcc Exception: ", ex);
+
+ }
+ return success;
+ }
+
+ private void refreshUPLMNListPreference(ArrayList<UPLMNInfoWithEf> list) {
+ if (mUPLMNListContainer.getPreferenceCount() != 0) {
+ mUPLMNListContainer.removeAll();
+ }
+
+ if (this.mPreferenceMap != null) {
+ mPreferenceMap.clear();
+ }
+
+ if (mUPLMNList != null) {
+ mUPLMNList.clear();
+ }
+ mUPLMNList = list;
+ if (list == null) {
+ log("refreshUPLMNListPreference : NULL UPLMN list!");
+ } else {
+ log("refreshUPLMNListPreference : list.size()" + list.size());
+ }
+
+ if (list == null || list.size() == 0) {
+ if (DBG) {
+ log("refreshUPLMNListPreference : NULL UPLMN list!");
+ }
+ if (list == null) {
+ mUPLMNList = new ArrayList<UPLMNInfoWithEf>();
+ }
+ return;
+ }
+
+ for (UPLMNInfoWithEf network : list) {
+ addUPLMNPreference(network);
+ if (DBG) {
+ log(network.toString());
+ }
+ }
+ }
+
+ class UPLMNInfoWithEf {
+
+ private String mOperatorNumeric;
+
+ private int mNetworkMode;
+ private int mPriority; // priority is the index of the plmn in the list.
+
+ public String getOperatorNumeric() {
+ return mOperatorNumeric;
+ }
+
+ public int getNetworMode() {
+ return mNetworkMode;
+ }
+
+ public int getPriority() {
+ return mPriority;
+ }
+
+ public void setOperatorNumeric(String operatorNumeric) {
+ this.mOperatorNumeric = operatorNumeric;
+ }
+
+ public void setPriority(int index) {
+ this.mPriority = index;
+ }
+
+ public UPLMNInfoWithEf(String operatorNumeric, int mNetworkMode,
+ int mPriority) {
+ this.mOperatorNumeric = operatorNumeric;
+ this.mNetworkMode = mNetworkMode;
+ this.mPriority = mPriority;
+ }
+
+ public String toString() {
+ return "UPLMNInfoWithEf " + mOperatorNumeric + "/" + mNetworkMode
+ + "/" + mPriority;
+ }
+ }
+
+ class PriorityCompare implements Comparator<UPLMNInfoWithEf> {
+
+ public int compare(UPLMNInfoWithEf object1, UPLMNInfoWithEf object2) {
+ return (object1.getPriority() - object2.getPriority());
+ }
+ }
+
+ private void addUPLMNPreference(UPLMNInfoWithEf network) {
+ Preference pref = new Preference(this);
+ String plmnName = network.getOperatorNumeric();
+ String extendName = getNetworkModeString(network.getNetworMode(), plmnName);
+ pref.setTitle(plmnName + "(" + extendName + ")");
+ mUPLMNListContainer.addPreference(pref);
+ mPreferenceMap.put(pref, network);
+ }
+
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
+ Preference preference) {
+ Intent intent = new Intent(this, UserPLMNEditorActivity.class);
+ UPLMNInfoWithEf info = this.mPreferenceMap.get(preference);
+ mOldInfo = info;
+
+ intent.putExtra(UserPLMNEditorActivity.UPLMN_CODE, info.getOperatorNumeric());
+ intent.putExtra(UserPLMNEditorActivity.UPLMN_PRIORITY, info.getPriority());
+ intent.putExtra(UserPLMNEditorActivity.UPLMN_SERVICE, info.getNetworMode());
+ intent.putExtra(UserPLMNEditorActivity.UPLMN_ADD, false);
+ intent.putExtra(UserPLMNEditorActivity.UPLMN_SIZE, mUPLMNList.size());
+ startActivityForResult(intent, UPLMNLIST_EDIT);
+ return true;
+ }
+
+ protected void onActivityResult(final int requestCode,
+ final int resultCode, final Intent intent) {
+ log("resultCode = " + resultCode + ", requestCode = " + requestCode);
+
+ if (intent != null) {
+ UPLMNInfoWithEf newInfo = createNetworkInfofromIntent(intent);
+ if (resultCode == UserPLMNEditorActivity.RESULT_CODE_DELETE) {
+ handleSetUPLMN(handleDeleteList(mOldInfo));
+ } else if (resultCode == UserPLMNEditorActivity.RESULT_CODE_EDIT) {
+ if (requestCode == UPLMNLIST_ADD) {
+ handleAddList(newInfo);
+ } else if (requestCode == UPLMNLIST_EDIT) {
+ handleSetUPLMN(handleModifiedList(newInfo, mOldInfo));
+ }
+ }
+ }
+ }
+
+ private UPLMNInfoWithEf createNetworkInfofromIntent(Intent intent) {
+ String numberName = intent.getStringExtra(UserPLMNEditorActivity.UPLMN_CODE);
+ int priority = intent.getIntExtra(UserPLMNEditorActivity.UPLMN_PRIORITY, 0);
+ int act = intent.getIntExtra(UserPLMNEditorActivity.UPLMN_SERVICE, 0);
+ return new UPLMNInfoWithEf(numberName, act, priority);
+ }
+
+ public static byte[] stringToBcdPlmn(String str) {
+ if (str.length() == 5) {
+ str = str + "f";
+ }
+
+ byte[] trans = IccUtils.hexStringToBytes(str);
+
+ byte[] data = new byte[3];;
+ data[0] = (byte) ((trans[0] >> 4) | ((trans[0] << 4) & 0xF0));
+ data[1] = (byte) ((trans[1] >> 4) | ((trans[2] << 4) & 0xF0));
+ data[2] = (byte) ((trans[2] & 0xF0) | (trans[1] & 0xF));
+
+ return data;
+ }
+
+ private void handleSetUPLMN(ArrayList<UPLMNInfoWithEf> list) {
+ showSavingDialog();
+ byte[] data = new byte[mNumRec * UPLMN_SEL_DATA_LEN];
+ byte[] mccmnc = new byte[6];
+ for (int i = 0; i < mNumRec; i++) {
+ data[i * UPLMN_SEL_DATA_LEN] = (byte) 0xFF;
+ data[i * UPLMN_SEL_DATA_LEN + 1] = (byte) 0xFF;
+ data[i * UPLMN_SEL_DATA_LEN + 2] = (byte) 0xFF;
+
+ data[i * UPLMN_SEL_DATA_LEN + 3] = 0;
+ data[i * UPLMN_SEL_DATA_LEN + 4] = 0;
+ }
+ for (int i = 0; ((i < list.size()) && (i < mNumRec)); i++) {
+ UPLMNInfoWithEf ni = list.get(i);
+ String strOperNumeric = ni.getOperatorNumeric();
+ if (TextUtils.isEmpty(strOperNumeric)) {
+ break;
+ }
+ log("strOperNumeric = " + strOperNumeric);
+
+ System.arraycopy(stringToBcdPlmn(strOperNumeric),
+ 0, data, i * UPLMN_SEL_DATA_LEN, 3);
+ log("data[0] = " + data[i * UPLMN_SEL_DATA_LEN]);
+ log("data[1] = " + data[i * UPLMN_SEL_DATA_LEN +1]);
+ log("data[2] = " + data[i * UPLMN_SEL_DATA_LEN +2]);
+
+ int accessTech = convertNetworkMode2AccessTech(ni.getNetworMode());
+ data[i * UPLMN_SEL_DATA_LEN + 3] = (byte) (accessTech >> 8);
+ data[i * UPLMN_SEL_DATA_LEN + 4] = (byte) (accessTech & 0xFF);
+ log("accessTech = " + accessTech);
+ log("data[3] = " + data[i * UPLMN_SEL_DATA_LEN +3]);
+ log("data[4] = " + data[i * UPLMN_SEL_DATA_LEN +4]);
+ }
+
+ log("update EFuplmn Start.");
+ writeEfToIcc(data, IccConstants.EF_PLMN_W_ACT);
+ }
+
+ private void handleAddList(UPLMNInfoWithEf newInfo) {
+ log("handleAddList: add new network: " + newInfo);
+ dumpUPLMNInfo(mUPLMNList);
+ ArrayList<UPLMNInfoWithEf> list = new ArrayList<UPLMNInfoWithEf>();
+ for (int i = 0; i < mUPLMNList.size(); i++) {
+ list.add(mUPLMNList.get(i));
+ }
+ PriorityCompare pc = new PriorityCompare();
+ int position = Collections.binarySearch(mUPLMNList, newInfo, pc);
+ if (position >= 0)
+ list.add(position, newInfo);
+ else
+ list.add(newInfo);
+ updateListPriority(list);
+ dumpUPLMNInfo(list);
+ handleSetUPLMN(list);
+ }
+
+ private void dumpUPLMNInfo(List<UPLMNInfoWithEf> list) {
+ if (!DBG) {
+ return;
+ }
+ for (int i = 0; i < list.size(); i++) {
+ log("dumpUPLMNInfo : " + list.get(i).toString());
+ }
+ }
+
+ private ArrayList<UPLMNInfoWithEf> handleModifiedList(
+ UPLMNInfoWithEf newInfo, UPLMNInfoWithEf oldInfo) {
+ log("handleModifiedList: change old info: " + oldInfo.toString()
+ + " new info: " + newInfo.toString());
+ dumpUPLMNInfo(mUPLMNList);
+
+ PriorityCompare pc = new PriorityCompare();
+ int oldposition = Collections.binarySearch(mUPLMNList, oldInfo, pc);
+ int newposition = Collections.binarySearch(mUPLMNList, newInfo, pc);
+
+ ArrayList<UPLMNInfoWithEf> list = new ArrayList<UPLMNInfoWithEf>();
+ for (int i = 0; i < mUPLMNList.size(); i++) {
+ list.add(mUPLMNList.get(i));
+ }
+
+ if (oldposition > newposition) {
+ list.remove(oldposition);
+ list.add(newposition, newInfo);
+ } else if (oldposition < newposition) {
+ list.add(newposition + 1, newInfo);
+ list.remove(oldposition);
+ } else {
+ list.remove(oldposition);
+ list.add(oldposition, newInfo);
+ }
+
+ updateListPriority(list);
+ dumpUPLMNInfo(list);
+ return list;
+ }
+
+ private void updateListPriority(ArrayList<UPLMNInfoWithEf> list) {
+ int priority = 0;
+ for (UPLMNInfoWithEf info : list) {
+ info.setPriority(priority++);
+ }
+ }
+
+ private ArrayList<UPLMNInfoWithEf> handleDeleteList(UPLMNInfoWithEf network) {
+ log("handleDeleteList : " + network.toString());
+ dumpUPLMNInfo(mUPLMNList);
+
+ ArrayList<UPLMNInfoWithEf> list = new ArrayList<UPLMNInfoWithEf>();
+ PriorityCompare pc = new PriorityCompare();
+ int position = Collections.binarySearch(mUPLMNList, network, pc);
+
+ for (int i = 0; i < mUPLMNList.size(); i++) {
+ list.add(mUPLMNList.get(i));
+ }
+
+ if (position >= 0) {
+ list.remove(position);
+ }
+ network.setOperatorNumeric(null);
+ list.add(network);
+
+ updateListPriority(list);
+ dumpUPLMNInfo(list);
+
+ return list;
+ }
+
+ private class MyHandler extends Handler {
+ private static final int MESSAGE_GET_UPLMN_LIST = 0;
+
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_GET_UPLMN_LIST:
+ handleGetUPLMNList(msg);
+ break;
+ default:
+ break;
+ }
+ }
+
+ public void handleGetUPLMNList(Message msg) {
+ if (DBG) {
+ log("handleGetUPLMNList: done");
+ }
+
+ if (msg.arg2 == MyHandler.MESSAGE_GET_UPLMN_LIST) {
+ onFinished(mUPLMNListContainer, true);
+ } else {
+ onFinished(mUPLMNListContainer, false);
+ }
+
+ AsyncResult ar = (AsyncResult) msg.obj;
+ if (ar.exception != null) {
+ log("handleGetUPLMNList with exception = "
+ + ar.exception);
+ if (mUPLMNList == null) {
+ mUPLMNList = new ArrayList<UPLMNInfoWithEf>();
+ }
+ } else {
+ refreshUPLMNListPreference((ArrayList<UPLMNInfoWithEf>) ar.result);
+ }
+ }
+ }
+
+ public void handleGetEFDone(byte[] data) {
+ if (DBG) {
+ log("handleGetEFDone: done");
+ }
+
+ mNumRec = data.length / UPLMN_SEL_DATA_LEN;
+ log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data));
+
+ PlmnActRecord[] plmnActRecords = PlmnActRecord.getRecords(data);
+ log("PlmnActRecords=" + Arrays.toString(plmnActRecords));
+
+ ArrayList<UPLMNInfoWithEf> ret = new ArrayList<UPLMNInfoWithEf>();
+ int i = 0;
+ String INVALID_PLMN_PREFIX = "FFFFF";
+ for (PlmnActRecord record : plmnActRecords) {
+ if(!record.plmn.regionMatches(
+ true, 0, INVALID_PLMN_PREFIX, 0, INVALID_PLMN_PREFIX.length())
+ && record.accessTechs != -1 && !TextUtils.isEmpty(record.plmn)
+ && record.plmn.length() >= 5){
+ ret.add(new UPLMNInfoWithEf(
+ record.plmn,
+ convertAccessTech2NetworkMode(record.accessTechs),
+ i));
+ }
+ i++;
+ }
+
+ Message message = mHandler.obtainMessage();
+ message.what = MyHandler.MESSAGE_GET_UPLMN_LIST;
+ if (ret == null) {
+ log("handleGetEFDone : NULL ret list!");
+ } else {
+ log("handleGetEFDone : ret.size()" + ret.size());
+ }
+
+ message.obj = new AsyncResult(message.obj, (Object) ret, null);
+ mHandler.sendMessage(message);
+ }
+
+ private int convertAccessTech2NetworkMode(int accessTechs) {
+ int networkMode = 0;
+
+ if ((accessTechs & PlmnActRecord.ACCESS_TECH_EUTRAN) != 0) {
+ networkMode = networkMode | LTE_MASK;
+ }
+ if ((accessTechs & PlmnActRecord.ACCESS_TECH_UTRAN) != 0) {
+ networkMode = networkMode | UMTS_MASK;
+ }
+ if ((accessTechs & PlmnActRecord.ACCESS_TECH_GSM) != 0) {
+ networkMode = networkMode | GSM_MASK;
+ }
+ if ((accessTechs & PlmnActRecord.ACCESS_TECH_GSM_COMPACT) != 0) {
+ networkMode = networkMode | GSM_COMPACT_MASK;
+ }
+
+ return networkMode;
+ }
+
+ private int convertNetworkMode2AccessTech(int networkMode) {
+ int accessTechs = 0;
+
+ if ((networkMode & LTE_MASK) != 0) {
+ accessTechs = accessTechs | PlmnActRecord.ACCESS_TECH_EUTRAN;
+ }
+ if ((networkMode & UMTS_MASK) != 0) {
+ accessTechs = accessTechs | PlmnActRecord.ACCESS_TECH_UTRAN;
+ }
+ if ((networkMode & GSM_MASK) != 0) {
+ accessTechs = accessTechs | PlmnActRecord.ACCESS_TECH_GSM;
+ }
+ if ((networkMode & GSM_COMPACT_MASK) != 0) {
+ accessTechs = accessTechs | PlmnActRecord.ACCESS_TECH_GSM_COMPACT;
+ }
+
+ return accessTechs;
+ }
+
+ private String getNetworkModeString(int EFNWMode, String plmn) {
+ Log.d(LOG_TAG, "plmn = " + plmn);
+ int index = UserPLMNEditorActivity.convertEFMode2Ap(EFNWMode);
+ String[] CuPlmnArray = getResources().getStringArray(R.array.uplmn_cu_mcc_mnc_values);
+ for (String CuPlmn : CuPlmnArray) {
+ if (plmn.equals(CuPlmn)) {
+ return getResources().getStringArray
+ (R.array.uplmn_prefer_network_mode_w_choices)[index];
+ }
+ }
+ return getResources().getStringArray(R.array.uplmn_prefer_network_mode_td_choices)[index];
+ }
+
+ private void setScreenEnabled() {
+ getPreferenceScreen().setEnabled(!mAirplaneModeOn);
+ invalidateOptionsMenu();
+ }
+
+ private static void log(String msg) {
+ Log.d(LOG_TAG, msg);
+ }
+}
diff --git a/src/com/android/settings/network/telephony/UserPLMNPreferenceController.java b/src/com/android/settings/network/telephony/UserPLMNPreferenceController.java
new file mode 100755
index 0000000000..76008cdbd1
--- /dev/null
+++ b/src/com/android/settings/network/telephony/UserPLMNPreferenceController.java
@@ -0,0 +1,83 @@
+/**
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.android.settings.network.telephony;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.PersistableBundle;
+import android.telephony.CarrierConfigManager;
+import android.telephony.SubscriptionManager;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+
+import com.android.settings.network.telephony.UserPLMNListActivity;
+
+/**
+ * Preference controller for "User PLMN Settings"
+ */
+public class UserPLMNPreferenceController extends TelephonyBasePreferenceController {
+
+ @VisibleForTesting
+ CarrierConfigManager mCarrierConfigManager;
+
+ public UserPLMNPreferenceController(Context context, String key) {
+ super(context, key);
+ mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
+ }
+
+ public void init(int subId) {
+ mSubId = subId;
+ }
+
+ @Override
+ public int getAvailabilityStatus(int subId) {
+ return SubscriptionManager.isValidSubscriptionId(subId)
+ ? AVAILABLE
+ : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (getPreferenceKey().equals(preference.getKey())) {
+ final Intent intent = new Intent(mContext, UserPLMNListActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, mSubId);
+ mContext.startActivity(intent);
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java
index 2d7ba38a80..fbb0de9b83 100644
--- a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java
+++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java
@@ -36,6 +36,7 @@ import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
+import com.android.ims.ImsConfig;
import com.android.settings.R;
import com.android.settings.network.ims.WifiCallingQueryImsState;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -155,6 +156,9 @@ public class WifiCallingPreferenceController extends TelephonyBasePreferenceCont
case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED:
resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary;
break;
+ case ImsConfig.WfcModeFeatureValueConstants.IMS_PREFERRED:
+ resId = com.android.internal.R.string.wfc_mode_ims_preferred_summary;
+ break;
default:
break;
}
diff --git a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java
index 028c4e77a7..a02d833e60 100644
--- a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java
+++ b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java
@@ -43,6 +43,8 @@ import androidx.preference.SwitchPreference;
import com.android.settings.R;
import com.android.settings.network.AllowedNetworkTypesListener;
+import com.android.settings.network.SubscriptionsChangeListener;
+import com.android.settings.network.telephony.Enhanced4gBasePreferenceController;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settings.network.telephony.TelephonyTogglePreferenceController;
import com.android.settingslib.utils.ThreadUtils;
@@ -56,7 +58,9 @@ import java.util.concurrent.TimeUnit;
* Preference controller for "Auto Select Network"
*/
public class AutoSelectPreferenceController extends TelephonyTogglePreferenceController
- implements LifecycleObserver{
+ implements LifecycleObserver,
+ Enhanced4gBasePreferenceController.On4gLteUpdateListener,
+ SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
private static final long MINIMUM_DIALOG_TIME_MILLIS = TimeUnit.SECONDS.toMillis(1);
private final Handler mUiHandler;
@@ -65,6 +69,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
private TelephonyManager mTelephonyManager;
private boolean mOnlyAutoSelectInHome;
private List<OnNetworkSelectModeListener> mListeners;
+ private SubscriptionsChangeListener mSubscriptionsListener;
@VisibleForTesting
ProgressDialog mProgressDialog;
@VisibleForTesting
@@ -80,6 +85,12 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
new HandlerExecutor(mUiHandler));
mAllowedNetworkTypesListener.setAllowedNetworkTypesListener(
() -> updatePreference());
+ mSubscriptionsListener = new SubscriptionsChangeListener(context, this);
+ }
+
+ @Override
+ public void on4gLteUpdated() {
+ updateState(mSwitchPreference);
}
private void updatePreference() {
@@ -94,11 +105,13 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
@OnLifecycleEvent(ON_START)
public void onStart() {
mAllowedNetworkTypesListener.register(mContext, mSubId);
+ mSubscriptionsListener.start();
}
@OnLifecycleEvent(ON_STOP)
public void onStop() {
mAllowedNetworkTypesListener.unregister(mContext, mSubId);
+ mSubscriptionsListener.stop();
}
@Override
@@ -124,8 +137,12 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
@Override
public void updateState(Preference preference) {
super.updateState(preference);
-
preference.setSummary(null);
+ final int phoneType = mTelephonyManager.getPhoneType();
+ if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
+ preference.setEnabled(false);
+ return;
+ }
final ServiceState serviceState = mTelephonyManager.getServiceState();
if (serviceState == null) {
preference.setEnabled(false);
@@ -230,6 +247,14 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon
}
}
+ @Override
+ public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+ }
+
+ @Override
+ public void onSubscriptionsChanged() {
+ updateState(mSwitchPreference);
+ }
/**
* Callback when network select mode is changed
*
diff --git a/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java b/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java
index 54f5ce15d7..fa488744e8 100644
--- a/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java
+++ b/src/com/android/settings/network/telephony/gsm/OpenNetworkSelectPagePreferenceController.java
@@ -34,6 +34,8 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.network.AllowedNetworkTypesListener;
+import com.android.settings.network.SubscriptionsChangeListener;
+import com.android.settings.network.telephony.Enhanced4gBasePreferenceController;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settings.network.telephony.TelephonyBasePreferenceController;
@@ -42,12 +44,16 @@ import com.android.settings.network.telephony.TelephonyBasePreferenceController;
*/
public class OpenNetworkSelectPagePreferenceController extends
TelephonyBasePreferenceController implements
- AutoSelectPreferenceController.OnNetworkSelectModeListener, LifecycleObserver {
+ AutoSelectPreferenceController.OnNetworkSelectModeListener,
+ Enhanced4gBasePreferenceController.On4gLteUpdateListener,
+ LifecycleObserver,
+ SubscriptionsChangeListener.SubscriptionsChangeListenerClient {
private TelephonyManager mTelephonyManager;
private Preference mPreference;
private PreferenceScreen mPreferenceScreen;
private AllowedNetworkTypesListener mAllowedNetworkTypesListener;
+ private SubscriptionsChangeListener mSubscriptionsListener;
public OpenNetworkSelectPagePreferenceController(Context context, String key) {
super(context, key);
@@ -57,9 +63,15 @@ public class OpenNetworkSelectPagePreferenceController extends
context.getMainExecutor());
mAllowedNetworkTypesListener.setAllowedNetworkTypesListener(
() -> updatePreference());
+ mSubscriptionsListener = new SubscriptionsChangeListener(context, this);
}
+ @Override
+ public void on4gLteUpdated() {
+ updateState(mPreference);
+ }
+
private void updatePreference() {
if (mPreferenceScreen != null) {
displayPreference(mPreferenceScreen);
@@ -79,11 +91,13 @@ public class OpenNetworkSelectPagePreferenceController extends
@OnLifecycleEvent(ON_START)
public void onStart() {
mAllowedNetworkTypesListener.register(mContext, mSubId);
+ mSubscriptionsListener.start();
}
@OnLifecycleEvent(ON_STOP)
public void onStop() {
mAllowedNetworkTypesListener.unregister(mContext, mSubId);
+ mSubscriptionsListener.stop();
}
@Override
@@ -96,8 +110,13 @@ public class OpenNetworkSelectPagePreferenceController extends
@Override
public void updateState(Preference preference) {
super.updateState(preference);
+ final int phoneType = mTelephonyManager.getPhoneType();
+ if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
+ preference.setEnabled(false);
+ } else {
preference.setEnabled(mTelephonyManager.getNetworkSelectionMode()
!= TelephonyManager.NETWORK_SELECTION_MODE_AUTO);
+ }
Intent intent = new Intent();
intent.setClassName("com.android.settings",
@@ -128,4 +147,13 @@ public class OpenNetworkSelectPagePreferenceController extends
public void onNetworkSelectModeChanged() {
updateState(mPreference);
}
+
+ @Override
+ public void onAirplaneModeChanged(boolean airplaneModeEnabled) {
+ }
+
+ @Override
+ public void onSubscriptionsChanged() {
+ updateState(mPreference);
+ }
}
diff --git a/src/com/android/settings/notification/CallConnectedTonePreferenceController.java b/src/com/android/settings/notification/CallConnectedTonePreferenceController.java
new file mode 100644
index 0000000000..9498485990
--- /dev/null
+++ b/src/com/android/settings/notification/CallConnectedTonePreferenceController.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 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.notification;
+
+import static com.android.settings.notification.SettingPref.TYPE_SYSTEM;
+
+import android.content.Context;
+import android.provider.Settings.System;
+
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.Utils;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+
+public class CallConnectedTonePreferenceController extends SettingPrefController {
+
+ private static final String KEY_CALL_CONNECTED_TONES = "call_connected_tones";
+
+ public CallConnectedTonePreferenceController(Context context, SettingsPreferenceFragment parent,
+ Lifecycle lifecycle) {
+ super(context, parent, lifecycle);
+
+ int defaultOn = mContext.getResources().getInteger(R.integer.
+ config_default_tone_after_connected);
+ mPreference = new SettingPref(
+ TYPE_SYSTEM, KEY_CALL_CONNECTED_TONES, System.CALL_CONNECTED_TONE_ENABLED,
+ defaultOn) {
+ @Override
+ public boolean isApplicable(Context context) {
+ return context.getResources().getBoolean(R.bool.config_show_connect_tone_ui);
+ }
+ };
+ }
+
+}
diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java
index 85623b8a9f..94cd529741 100644
--- a/src/com/android/settings/notification/SoundSettings.java
+++ b/src/com/android/settings/notification/SoundSettings.java
@@ -248,6 +248,8 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult
// === Other Sound Settings ===
final DialPadTonePreferenceController dialPadTonePreferenceController =
new DialPadTonePreferenceController(context, fragment, lifecycle);
+ final CallConnectedTonePreferenceController callConnectedTonePreferenceController =
+ new CallConnectedTonePreferenceController(context, fragment, lifecycle);
final ScreenLockSoundPreferenceController screenLockSoundPreferenceController =
new ScreenLockSoundPreferenceController(context, fragment, lifecycle);
final ChargingSoundPreferenceController chargingSoundPreferenceController =
@@ -266,6 +268,7 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult
new EmergencyTonePreferenceController(context, fragment, lifecycle);
controllers.add(dialPadTonePreferenceController);
+ controllers.add(callConnectedTonePreferenceController);
controllers.add(screenLockSoundPreferenceController);
controllers.add(chargingSoundPreferenceController);
controllers.add(dockingSoundPreferenceController);
@@ -277,6 +280,7 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult
controllers.add(new PreferenceCategoryController(context,
"other_sounds_and_vibrations_category").setChildren(
Arrays.asList(dialPadTonePreferenceController,
+ callConnectedTonePreferenceController,
screenLockSoundPreferenceController,
chargingSoundPreferenceController,
dockingSoundPreferenceController,
diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java
index a1826ba0cb..87ea9c2e62 100644
--- a/src/com/android/settings/password/ChooseLockGeneric.java
+++ b/src/com/android/settings/password/ChooseLockGeneric.java
@@ -215,6 +215,7 @@ public class ChooseLockGeneric extends SettingsActivity {
mLockPatternUtils = new LockPatternUtils(activity);
mIsSetNewPassword = ACTION_SET_NEW_PARENT_PROFILE_PASSWORD.equals(chooseLockAction)
|| ACTION_SET_NEW_PASSWORD.equals(chooseLockAction);
+ mLockPatternUtils.sanitizePassword();
// Defaults to needing to confirm credentials
final boolean confirmCredentials = intent
@@ -901,6 +902,7 @@ public class ChooseLockGeneric extends SettingsActivity {
@Override
public void onDestroy() {
super.onDestroy();
+ mLockPatternUtils.sanitizePassword();
if (mUserPassword != null) {
mUserPassword.zeroize();
}
diff --git a/src/com/android/settings/security/SimLockPreferenceController.java b/src/com/android/settings/security/SimLockPreferenceController.java
index 3b8588852e..28f6924337 100644
--- a/src/com/android/settings/security/SimLockPreferenceController.java
+++ b/src/com/android/settings/security/SimLockPreferenceController.java
@@ -112,8 +112,10 @@ public class SimLockPreferenceController extends BasePreferenceController {
.createForSubscriptionId(subInfo.getSubscriptionId());
final PersistableBundle bundle = mCarrierConfigManager.getConfigForSubId(
subInfo.getSubscriptionId());
+ final int simState = mTelephonyManager.getSimState(subInfo.getSimSlotIndex());
if (telephonyManager.hasIccCard() && bundle != null
- && !bundle.getBoolean(CarrierConfigManager.KEY_HIDE_SIM_LOCK_SETTINGS_BOOL)) {
+ && !bundle.getBoolean(CarrierConfigManager.KEY_HIDE_SIM_LOCK_SETTINGS_BOOL)
+ && (simState != TelephonyManager.SIM_STATE_NOT_READY)) {
// one or more sims show sim lock setting UI.
return false;
}
diff --git a/src/com/android/settings/widget/GroupOptionsPreference.java b/src/com/android/settings/widget/GroupOptionsPreference.java
new file mode 100644
index 0000000000..eddbe5f85f
--- /dev/null
+++ b/src/com/android/settings/widget/GroupOptionsPreference.java
@@ -0,0 +1,414 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.android.settings.widget;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import androidx.annotation.StringRes;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceViewHolder;
+
+import com.android.settings.R;
+
+/** A preference which provide Group action buttons (connect, disconnect,
+ * refresh, cacnelRefresh, forget
+ **/
+
+public class GroupOptionsPreference extends Preference {
+
+ private static final String TAG = "GroupOptionsPreference";
+ private final ButtonInfo mBtnAddSrcGroup = new ButtonInfo();
+ private final ButtonInfo mBtnConnect = new ButtonInfo();
+ private final ButtonInfo mBtnForget = new ButtonInfo();
+ private final ButtonInfo mBtnDisconnect = new ButtonInfo();
+ private final ButtonInfo mBtnRefresh = new ButtonInfo();
+ private final ButtonInfo mBtnCancelRefresh = new ButtonInfo();
+ private final TextViewInfo mTvGroupId = new TextViewInfo();
+ private final TextViewInfo mTvStatus = new TextViewInfo();
+ private final ProgressInfo mProgressScan = new ProgressInfo();
+
+ public GroupOptionsPreference(Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public GroupOptionsPreference(Context context, AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init();
+ }
+
+ public GroupOptionsPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ private void init() {
+ setLayoutResource(R.layout.bluetooth_group_options);
+ setSelectable(false);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ holder.setDividerAllowedAbove(true);
+ holder.setDividerAllowedBelow(true);
+ mBtnAddSrcGroup.mButton = (Button) holder.findViewById(R.id.id_btn_group_add_source);
+ mBtnConnect.mButton = (Button) holder.findViewById(R.id.id_btn_connect);
+ mBtnForget.mButton = (Button) holder.findViewById(R.id.id_btn_forget);
+ mBtnDisconnect.mButton = (Button) holder.findViewById(R.id.id_btn_disconnect);
+ mBtnRefresh.mButton = (Button) holder.findViewById(R.id.id_btn_refresh);
+ mBtnCancelRefresh.mButton = (Button) holder.findViewById(R.id.id_btn_refresh_cancel);
+ mTvGroupId.mTextView = (TextView)holder.findViewById(R.id.id_tv_groupid);
+ mTvStatus.mTextView =(TextView)holder.findViewById(R.id.id_tv_status);
+ mProgressScan.mProgress = (ProgressBar)holder.findViewById(R.id.id_progress_group_scan);
+ mBtnAddSrcGroup.setUpButton();
+ mBtnConnect.setUpButton();
+ mBtnForget.setUpButton();
+ mBtnDisconnect.setUpButton();
+ mBtnRefresh.setUpButton();
+ mBtnCancelRefresh.setUpButton();
+ mTvGroupId.setUpTextView();
+ mTvStatus.setUpTextView();
+ mProgressScan.setUpProgress();
+ }
+
+ public GroupOptionsPreference setAddSourceGroupButtonVisible(boolean isVisible) {
+ if (isVisible != mBtnAddSrcGroup.mIsVisible) {
+ mBtnAddSrcGroup.mIsVisible = isVisible;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setAddSourceGroupButtonText(@StringRes int textResId) {
+ final String newText = getContext().getString(textResId);
+ if (!TextUtils.equals(newText, mBtnAddSrcGroup.mText)) {
+ mBtnAddSrcGroup.mText = newText;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setAddSourceGroupButtonEnabled(boolean isEnabled) {
+ if (isEnabled != mBtnAddSrcGroup.mIsEnabled) {
+ mBtnAddSrcGroup.mIsEnabled = isEnabled;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setAddSourceGroupButtonOnClickListener(
+ View.OnClickListener listener) {
+ if (listener != mBtnAddSrcGroup.mListener) {
+ mBtnAddSrcGroup.mListener = listener;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setConnectButtonVisible(boolean isVisible) {
+ if (isVisible != mBtnConnect.mIsVisible) {
+ mBtnConnect.mIsVisible = isVisible;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setConnectButtonText(@StringRes int textResId) {
+ final String newText = getContext().getString(textResId);
+ if (!TextUtils.equals(newText, mBtnConnect.mText)) {
+ mBtnConnect.mText = newText;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setConnectButtonEnabled(boolean isEnabled) {
+ if (isEnabled != mBtnConnect.mIsEnabled) {
+ mBtnConnect.mIsEnabled = isEnabled;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setConnectButtonOnClickListener(
+ View.OnClickListener listener) {
+ if (listener != mBtnConnect.mListener) {
+ mBtnConnect.mListener = listener;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setForgettButtonVisible(boolean isVisible) {
+ if (isVisible != mBtnForget.mIsVisible) {
+ mBtnForget.mIsVisible = isVisible;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setForgetButtonText(@StringRes int textResId) {
+ final String newText = getContext().getString(textResId);
+ if (!TextUtils.equals(newText, mBtnForget.mText)) {
+ mBtnForget.mText = newText;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setForgetButtonEnabled(boolean isEnabled) {
+ if (isEnabled != mBtnForget.mIsEnabled) {
+ mBtnForget.mIsEnabled = isEnabled;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setForgetButtonOnClickListener(
+ View.OnClickListener listener) {
+ if (listener != mBtnForget.mListener) {
+ mBtnForget.mListener = listener;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setDisconnectButtonVisible(boolean isVisible) {
+ if (isVisible != mBtnDisconnect.mIsVisible) {
+ mBtnDisconnect.mIsVisible = isVisible;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setDisconnectButtonText(@StringRes int textResId) {
+ final String newText = getContext().getString(textResId);
+ if (!TextUtils.equals(newText, mBtnDisconnect.mText)) {
+ mBtnDisconnect.mText = newText;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setDisconnectButtonEnabled(boolean isEnabled) {
+ if (isEnabled != mBtnDisconnect.mIsEnabled) {
+ mBtnDisconnect.mIsEnabled = isEnabled;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setDisconnectButtonOnClickListener(
+ View.OnClickListener listener) {
+ if (listener != mBtnDisconnect.mListener) {
+ mBtnDisconnect.mListener = listener;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setRefreshButtonVisible(boolean isVisible) {
+ if (isVisible != mBtnRefresh.mIsVisible) {
+ mBtnRefresh.mIsVisible = isVisible;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setRefreshButtonText(@StringRes int textResId) {
+ final String newText = getContext().getString(textResId);
+ if (!TextUtils.equals(newText, mBtnRefresh.mText)) {
+ mBtnRefresh.mText = newText;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setRefreshButtonEnabled(boolean isEnabled) {
+ if (isEnabled != mBtnRefresh.mIsEnabled) {
+ mBtnRefresh.mIsEnabled = isEnabled;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setRefreshButtonOnClickListener(
+ View.OnClickListener listener) {
+ if (listener != mBtnRefresh.mListener) {
+ mBtnRefresh.mListener = listener;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setCancelRefreshButtonText(@StringRes int textResId) {
+ final String newText = getContext().getString(textResId);
+ if (!TextUtils.equals(newText, mBtnCancelRefresh.mText)) {
+ mBtnCancelRefresh.mText = newText;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setCancelRefreshButtonVisible(boolean isVisible) {
+ if (isVisible != mBtnCancelRefresh.mIsVisible) {
+ mBtnCancelRefresh.mIsVisible = isVisible;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setCancelRefreshButtonEnabled(boolean isEnabled) {
+ if (isEnabled != mBtnCancelRefresh.mIsEnabled) {
+ mBtnCancelRefresh.mIsEnabled = isEnabled;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setCancelRefreshButtonOnClickListener(
+ View.OnClickListener listener) {
+ if (listener != mBtnCancelRefresh.mListener) {
+ mBtnCancelRefresh.mListener = listener;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setTvSetIdVisible(boolean isVisible) {
+ if (isVisible != mTvGroupId.mIsVisible) {
+ mTvGroupId.mIsVisible = isVisible;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setTextViewText(String newText) {
+ if (!TextUtils.equals(newText, mTvGroupId.mText)) {
+ mTvGroupId.mText = newText;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setTvStatusVisible(boolean isVisible) {
+ if (isVisible != mTvStatus.mIsVisible) {
+ mTvStatus.mIsVisible = isVisible;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setTexStatusText(@StringRes int textResId) {
+ final String newText = getContext().getString(textResId);
+ if (!TextUtils.equals(newText, mTvStatus.mText)) {
+ mTvStatus.mText = newText;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ public GroupOptionsPreference setProgressScanVisible(boolean isVisible) {
+ if (isVisible != mProgressScan.mIsVisible) {
+ mProgressScan.mIsVisible = isVisible;
+ notifyChanged();
+ }
+ return this;
+ }
+
+ static class ButtonInfo {
+ private Button mButton;
+ private CharSequence mText;
+ private View.OnClickListener mListener;
+ private boolean mIsEnabled = true;
+ private boolean mIsVisible = true;
+
+ void setUpButton() {
+ mButton.setText(mText);
+ mButton.setOnClickListener(mListener);
+ mButton.setEnabled(mIsEnabled);
+ mButton.setTypeface(null, Typeface.BOLD);
+ if (shouldBeVisible()) {
+ mButton.setVisibility(View.VISIBLE);
+ } else {
+ mButton.setVisibility(View.GONE);
+ }
+ }
+
+ private boolean shouldBeVisible() {
+ return mIsVisible && (!TextUtils.isEmpty(mText));
+ }
+ }
+
+ static class TextViewInfo {
+ private TextView mTextView;
+ private CharSequence mText;
+ private boolean mIsVisible = true;
+
+ void setUpTextView() {
+ mTextView.setText(mText);
+ mTextView.setTypeface(null, Typeface.BOLD);
+ if (shouldBeVisible()) {
+ mTextView.setVisibility(View.VISIBLE);
+ } else {
+ mTextView.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ private boolean shouldBeVisible() {
+ return mIsVisible && (!TextUtils.isEmpty(mText));
+ }
+ }
+
+ static class ProgressInfo {
+ private ProgressBar mProgress;
+ private boolean mIsVisible = true;
+ void setUpProgress() {
+ if (shouldBeVisible()) {
+ mProgress.setVisibility(View.VISIBLE);
+ } else {
+ mProgress.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ private boolean shouldBeVisible() {
+ return mIsVisible;
+ }
+ }
+}
diff --git a/src/com/android/settings/widget/GroupPreferenceCategory.java b/src/com/android/settings/widget/GroupPreferenceCategory.java
new file mode 100644
index 0000000000..06c7858bf9
--- /dev/null
+++ b/src/com/android/settings/widget/GroupPreferenceCategory.java
@@ -0,0 +1,66 @@
+/******************************************************************************
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+package com.android.settings.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+
+import androidx.preference.PreferenceCategory;
+
+/** A PreferenceCategory which holds setid
+ **/
+public class GroupPreferenceCategory extends PreferenceCategory {
+
+ private int mGroupId = -1;
+
+ public GroupPreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public GroupPreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public GroupPreferenceCategory(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public GroupPreferenceCategory(Context context) {
+ super(context);
+ }
+
+ public int getGroupId() {
+ return mGroupId;
+ }
+
+ public void setGroupId(int groupId) {
+ mGroupId = groupId;
+ }
+}
diff --git a/src/com/android/settings/wifi/WifiConfigController2.java b/src/com/android/settings/wifi/WifiConfigController2.java
index 127c882340..e9206bc054 100644
--- a/src/com/android/settings/wifi/WifiConfigController2.java
+++ b/src/com/android/settings/wifi/WifiConfigController2.java
@@ -203,6 +203,7 @@ public class WifiConfigController2 implements TextWatcher,
private TextView mProxyExclusionListView;
private TextView mProxyPacView;
private CheckBox mSharedCheckBox;
+ private CheckBox mShareThisWifiCheckBox;
private IpAssignment mIpAssignment = IpAssignment.UNASSIGNED;
private ProxySettings mProxySettings = ProxySettings.UNASSIGNED;
@@ -292,11 +293,19 @@ public class WifiConfigController2 implements TextWatcher,
? View.GONE
: View.VISIBLE);
mSecurityInPosition = new Integer[WifiEntry.NUM_SECURITY_TYPES];
+ mShareThisWifiCheckBox = (CheckBox) mView.findViewById(R.id.share_this_wifi);
if (mWifiEntry == null) { // new network
configureSecuritySpinner();
mConfigUi.setSubmitButton(res.getString(R.string.wifi_save));
} else {
+ if (!mWifiManager.isWifiCoverageExtendFeatureEnabled()
+ || (mWifiEntry.getSecurity() != WifiEntry.SECURITY_NONE
+ && mWifiEntry.getSecurity() != WifiEntry.SECURITY_PSK)) {
+ mShareThisWifiCheckBox.setChecked(false);
+ mShareThisWifiCheckBox.setVisibility(View.GONE);
+ }
+
mConfigUi.setTitle(mWifiEntry.getTitle());
ViewGroup group = (ViewGroup) mView.findViewById(R.id.info);
@@ -304,6 +313,7 @@ public class WifiConfigController2 implements TextWatcher,
boolean showAdvancedFields = false;
if (mWifiEntry.isSaved()) {
WifiConfiguration config = mWifiEntry.getWifiConfiguration();
+ mShareThisWifiCheckBox.setChecked(config.shareThisAp);
mMeteredSettingsSpinner.setSelection(config.meteredOverride);
mHiddenSettingsSpinner.setSelection(config.hiddenSSID
? HIDDEN_NETWORK
@@ -597,6 +607,7 @@ public class WifiConfigController2 implements TextWatcher,
}
config.shared = mSharedCheckBox.isChecked();
+ config.shareThisAp = mShareThisWifiCheckBox.isChecked();
switch (mWifiEntrySecurity) {
case WifiEntry.SECURITY_NONE:
@@ -697,8 +708,10 @@ public class WifiConfigController2 implements TextWatcher,
if (config.enterpriseConfig.isAuthenticationSimBased()
&& mActiveSubscriptionInfos.size() > 0) {
- config.carrierId = mActiveSubscriptionInfos
- .get(mEapSimSpinner.getSelectedItemPosition()).getCarrierId();
+ SubscriptionInfo subInfo = mActiveSubscriptionInfos
+ .get(mEapSimSpinner.getSelectedItemPosition());
+ config.carrierId = subInfo.getCarrierId();
+ config.subscriptionId = subInfo.getSubscriptionId();
}
String caCert = (String) mEapCaCertSpinner.getSelectedItem();
@@ -1665,6 +1678,16 @@ public class WifiConfigController2 implements TextWatcher,
if (parent == mSecuritySpinner) {
// Convert menu position to actual Wi-Fi security type
mWifiEntrySecurity = mSecurityInPosition[position];
+
+ if (!mWifiManager.isWifiCoverageExtendFeatureEnabled()
+ || (mWifiEntrySecurity != WifiEntry.SECURITY_NONE
+ && mWifiEntrySecurity != WifiEntry.SECURITY_PSK)) {
+ mShareThisWifiCheckBox.setChecked(false);
+ mShareThisWifiCheckBox.setVisibility(View.GONE);
+ } else {
+ mShareThisWifiCheckBox.setVisibility(View.VISIBLE);
+ }
+
showSecurityFields(/* refreshEapMethods */ true, /* refreshCertificates */ true);
if (WifiDppUtils.isSupportEnrolleeQrCodeScanner(mContext, mWifiEntrySecurity)) {
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 4c7be5871d..44df512ada 100644..100755
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -190,6 +190,8 @@ public class WifiSettings extends RestrictedSettingsFragment
// Worker thread used for WifiPickerTracker work
private HandlerThread mWorkerThread;
+ private Handler mMainHandler;
+ private Handler mWorkerHandler;
@VisibleForTesting
WifiPickerTracker mWifiPickerTracker;
@@ -291,11 +293,13 @@ public class WifiSettings extends RestrictedSettingsFragment
return SystemClock.elapsedRealtime();
}
};
+
+ mMainHandler = new Handler(Looper.getMainLooper());
+ mWorkerHandler = mWorkerThread.getThreadHandler();
mWifiPickerTracker = FeatureFactory.getFactory(context)
.getWifiTrackerLibProvider()
.createWifiPickerTracker(getSettingsLifecycle(), context,
- new Handler(Looper.getMainLooper()),
- mWorkerThread.getThreadHandler(),
+ mMainHandler, mWorkerHandler,
elapsedRealtimeClock,
MAX_SCAN_AGE_MILLIS,
SCAN_INTERVAL_MILLIS,
@@ -367,6 +371,10 @@ public class WifiSettings extends RestrictedSettingsFragment
if (mWifiEnabler != null) {
mWifiEnabler.teardownSwitchController();
}
+
+ // remove all msg and callback in main handler and worker handler
+ mMainHandler.removeCallbacksAndMessages(null);
+ mWorkerHandler.removeCallbacksAndMessages(null);
mWorkerThread.quit();
super.onDestroyView();
@@ -377,6 +385,7 @@ public class WifiSettings extends RestrictedSettingsFragment
super.onStart();
mWifiEnabler = createWifiEnabler();
+ mWifiManager.allowConnectOnPartialScanResults(true);
if (mIsRestricted) {
restrictUi();
@@ -431,6 +440,7 @@ public class WifiSettings extends RestrictedSettingsFragment
public void onStop() {
getView().removeCallbacks(mUpdateWifiEntryPreferencesRunnable);
getView().removeCallbacks(mHideProgressBarRunnable);
+ mWifiManager.allowConnectOnPartialScanResults(false);
mIsWifiEntryListStale = true;
super.onStop();
}
@@ -651,7 +661,7 @@ public class WifiSettings extends RestrictedSettingsFragment
/** Called when the state of Wifi has changed. */
@Override
public void onWifiStateChanged() {
- if (mIsRestricted) {
+ if (mIsRestricted || isFinishingOrDestroyed()) {
return;
}
final int wifiState = mWifiPickerTracker.getWifiState();
@@ -689,6 +699,12 @@ public class WifiSettings extends RestrictedSettingsFragment
@Override
public void onWifiEntriesChanged() {
+ // do nothing if UI is finishing and destoryed status
+ if (isFinishingOrDestroyed()) {
+ Log.d(TAG, "onWifiEntriesChanged: isFinishingOrDestroyed true");
+ return;
+ }
+
if (mIsWifiEntryListStale) {
mIsWifiEntryListStale = false;
updateWifiEntryPreferences();
@@ -833,7 +849,10 @@ public class WifiSettings extends RestrictedSettingsFragment
mWifiEntryPreferenceCategory.addPreference(pref);
} else {
// Continuing showing progress bar for an additional delay to overlap with animation
- getView().postDelayed(mHideProgressBarRunnable, 1700 /* delay millis */);
+ final View view = getView();
+ if (null != view) {
+ view.postDelayed(mHideProgressBarRunnable, 1700 /* delay millis */);
+ }
}
mAddWifiNetworkPreference.setOrder(index++);
diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
index 19664be409..5b688ff473 100644
--- a/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
+++ b/src/com/android/settings/wifi/calling/WifiCallingSettingsForSub.java
@@ -345,6 +345,7 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
final CarrierConfigManager configManager = (CarrierConfigManager)
getSystemService(Context.CARRIER_CONFIG_SERVICE);
boolean isWifiOnlySupported = true;
+ boolean isImsPreferredSupported = false;
if (configManager != null) {
final PersistableBundle b = configManager.getConfigForSubId(mSubId);
@@ -358,6 +359,8 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
false);
isWifiOnlySupported = b.getBoolean(
CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL, true);
+ isImsPreferredSupported = b.getBoolean(
+ CarrierConfigManager.KEY_CARRIER_WFC_SUPPORTS_IMS_PREFERRED_BOOL, false);
}
}
@@ -368,37 +371,72 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
mButtonWfcRoamingMode.setDialogTitle(
res.getString(R.string.wifi_calling_roaming_mode_dialog_title));
+ Log.d(TAG, "isWifiOnlySupported = " + isWifiOnlySupported + " isImsPreferredSupported = "
+ + isImsPreferredSupported);
+
if (isWifiOnlySupported) {
- // Set string resources WITH option wifi only in mButtonWfcMode.
- mButtonWfcMode.setEntries(
- res.getStringArray(R.array.wifi_calling_mode_choices));
- mButtonWfcMode.setEntryValues(res.getStringArray(R.array.wifi_calling_mode_values));
- mButtonWfcMode.setEntrySummaries(
- res.getStringArray(R.array.wifi_calling_mode_summaries));
-
- // Set string resources WITH option wifi only in mButtonWfcRoamingMode.
- mButtonWfcRoamingMode.setEntries(
- res.getStringArray(R.array.wifi_calling_mode_choices_v2));
- mButtonWfcRoamingMode.setEntryValues(
- res.getStringArray(R.array.wifi_calling_mode_values));
- mButtonWfcRoamingMode.setEntrySummaries(
- res.getStringArray(R.array.wifi_calling_mode_summaries));
+ if (isImsPreferredSupported) {
+ mButtonWfcMode.setEntries(res.getStringArray(
+ R.array.wifi_calling_mode_choices_with_ims_preferred));
+ mButtonWfcMode.setEntryValues(res.getStringArray(
+ R.array.wifi_calling_mode_values_with_ims_preferred));
+ mButtonWfcMode.setEntrySummaries(res.getStringArray(
+ R.array.wifi_calling_mode_summaries_with_ims_preferred));
+
+ mButtonWfcRoamingMode.setEntries(res.getStringArray(
+ R.array.wifi_calling_mode_choices_v2_with_ims_preferred));
+ mButtonWfcRoamingMode.setEntryValues(res.getStringArray(
+ R.array.wifi_calling_mode_values_with_ims_preferred));
+ mButtonWfcRoamingMode.setEntrySummaries(res.getStringArray(
+ R.array.wifi_calling_mode_summaries_with_ims_preferred));
+ } else {
+ // Set string resources WITH option wifi only in mButtonWfcMode.
+ mButtonWfcMode.setEntries(
+ res.getStringArray(R.array.wifi_calling_mode_choices));
+ mButtonWfcMode.setEntryValues(res.getStringArray(R.array.wifi_calling_mode_values));
+ mButtonWfcMode.setEntrySummaries(
+ res.getStringArray(R.array.wifi_calling_mode_summaries));
+
+ // Set string resources WITH option wifi only in mButtonWfcRoamingMode.
+ mButtonWfcRoamingMode.setEntries(
+ res.getStringArray(R.array.wifi_calling_mode_choices_v2));
+ mButtonWfcRoamingMode.setEntryValues(
+ res.getStringArray(R.array.wifi_calling_mode_values));
+ mButtonWfcRoamingMode.setEntrySummaries(
+ res.getStringArray(R.array.wifi_calling_mode_summaries));
+ }
} else {
- // Set string resources WITHOUT option wifi only in mButtonWfcMode.
- mButtonWfcMode.setEntries(
- res.getStringArray(R.array.wifi_calling_mode_choices_without_wifi_only));
- mButtonWfcMode.setEntryValues(
- res.getStringArray(R.array.wifi_calling_mode_values_without_wifi_only));
- mButtonWfcMode.setEntrySummaries(
- res.getStringArray(R.array.wifi_calling_mode_summaries_without_wifi_only));
-
- // Set string resources WITHOUT option wifi only in mButtonWfcRoamingMode.
- mButtonWfcRoamingMode.setEntries(
- res.getStringArray(R.array.wifi_calling_mode_choices_v2_without_wifi_only));
- mButtonWfcRoamingMode.setEntryValues(
- res.getStringArray(R.array.wifi_calling_mode_values_without_wifi_only));
- mButtonWfcRoamingMode.setEntrySummaries(
- res.getStringArray(R.array.wifi_calling_mode_summaries_without_wifi_only));
+ if (isImsPreferredSupported) {
+ mButtonWfcMode.setEntries(res.getStringArray(
+ R.array.wifi_calling_mode_choices_without_wifi_only_with_ims_preferred));
+ mButtonWfcMode.setEntryValues(res.getStringArray(
+ R.array.wifi_calling_mode_values_without_wifi_only_with_ims_preferred));
+ mButtonWfcMode.setEntrySummaries(res.getStringArray(
+ R.array.wifi_calling_mode_summaries_without_wifi_only_with_ims_preferred));
+
+ mButtonWfcRoamingMode.setEntries(res.getStringArray(
+ R.array.wifi_calling_mode_choices_v2_without_wifi_only_with_ims_preferred));
+ mButtonWfcRoamingMode.setEntryValues(res.getStringArray(
+ R.array.wifi_calling_mode_values_without_wifi_only_with_ims_preferred));
+ mButtonWfcRoamingMode.setEntrySummaries(res.getStringArray(
+ R.array.wifi_calling_mode_summaries_without_wifi_only_with_ims_preferred));
+ } else {
+ // Set string resources WITHOUT option wifi only in mButtonWfcMode.
+ mButtonWfcMode.setEntries(
+ res.getStringArray(R.array.wifi_calling_mode_choices_without_wifi_only));
+ mButtonWfcMode.setEntryValues(
+ res.getStringArray(R.array.wifi_calling_mode_values_without_wifi_only));
+ mButtonWfcMode.setEntrySummaries(
+ res.getStringArray(R.array.wifi_calling_mode_summaries_without_wifi_only));
+
+ // Set string resources WITHOUT option wifi only in mButtonWfcRoamingMode.
+ mButtonWfcRoamingMode.setEntries(
+ res.getStringArray(R.array.wifi_calling_mode_choices_v2_without_wifi_only));
+ mButtonWfcRoamingMode.setEntryValues(
+ res.getStringArray(R.array.wifi_calling_mode_values_without_wifi_only));
+ mButtonWfcRoamingMode.setEntrySummaries(
+ res.getStringArray(R.array.wifi_calling_mode_summaries_without_wifi_only));
+ }
}
// NOTE: Buttons will be enabled/disabled in mTelephonyCallback
@@ -644,6 +682,9 @@ public class WifiCallingSettingsForSub extends SettingsPreferenceFragment
case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED:
resId = com.android.internal.R.string.wfc_mode_wifi_preferred_summary;
break;
+ case ImsConfig.WfcModeFeatureValueConstants.IMS_PREFERRED:
+ resId = com.android.internal.R.string.wfc_mode_ims_preferred_summary;
+ break;
default:
Log.e(TAG, "Unexpected WFC mode value: " + wfcMode);
}
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index 39a5431e63..b2ebb23229 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -439,7 +439,8 @@ public class WifiDppUtils {
return securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE
|| securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION
|| securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK
- || securityType == SoftApConfiguration.SECURITY_TYPE_OPEN;
+ || securityType == SoftApConfiguration.SECURITY_TYPE_OPEN
+ || securityType == SoftApConfiguration.SECURITY_TYPE_OWE;
}
private static boolean isSupportWifiDpp(Context context, int wifiEntrySecurity) {
diff --git a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
index a926360bd9..def8bb858b 100644
--- a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
+++ b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java
@@ -47,6 +47,7 @@ import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.Toast;
@@ -199,7 +200,10 @@ public class WifiP2pSettings extends DashboardFragment
}
@Override
- public void onActivityCreated(Bundle savedInstanceState) {
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ final View root = super.onCreateView(inflater, container, savedInstanceState);
+
final Activity activity = getActivity();
if (mWifiP2pManager == null) {
mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
@@ -332,8 +336,7 @@ public class WifiP2pSettings extends DashboardFragment
}
}
};
-
- super.onActivityCreated(savedInstanceState);
+ return root;
}
@Override
diff --git a/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceController.java
index 8a4be10598..1da3e72bf8 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherApBandPreferenceController.java
@@ -30,48 +30,79 @@ import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.FeatureFlags;
+import java.util.ArrayList;
+import java.util.Arrays;
public class WifiTetherApBandPreferenceController extends WifiTetherBasePreferenceController {
private static final String TAG = "WifiTetherApBandPref";
private static final String PREF_KEY = "wifi_tether_network_ap_band";
+ // Predefined Band 5Ghz / 6Ghz combinations.
+ // 1- 5Ghz/6Ghz prefer (default): prefers 5Ghz/6Ghz, but supports 2Ghz also.
+ // 2- 5Ghz/6Ghz only: strict 5Ghz/6Ghz band.
+ private static final int BAND_5GHZ = SoftApConfiguration.BAND_5GHZ | SoftApConfiguration.BAND_2GHZ;
+ private static final int BAND_6GHZ = SoftApConfiguration.BAND_6GHZ | SoftApConfiguration.BAND_2GHZ;
+
private String[] mBandEntries;
private String[] mBandSummaries;
private int mBandIndex;
+ private final Context mContext;
+ private boolean m5GHzSupported;
+ private boolean m6GHzSupported;
+ private String mCountryCode;
+
+ // Dual Band (2G + 5G)
+ public static final int BAND_BOTH_2G_5G = 1 << 4;
public WifiTetherApBandPreferenceController(Context context,
OnTetherConfigUpdateListener listener) {
super(context, listener);
+ mContext = context;
+
+ syncBandSupportAndCountryCode();
updatePreferenceEntries();
}
@Override
public void updateDisplay() {
final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
+ syncBandSupportAndCountryCode();
if (config == null) {
mBandIndex = SoftApConfiguration.BAND_2GHZ;
Log.d(TAG, "Updating band index to BAND_2GHZ because no config");
- } else if (is5GhzBandSupported()) {
- mBandIndex = validateSelection(config.getBand());
+ } else if (is5GhzBandSupported() || is6GhzBandSupported()) {
+ if (config.getBands().length == 2) {
+ if (config.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_OWE) {
+ mWifiManager.setSoftApConfiguration(
+ new SoftApConfiguration.Builder(config)
+ .setBand(SoftApConfiguration.BAND_2GHZ)
+ .build());
+ mBandIndex = SoftApConfiguration.BAND_2GHZ;
+ Log.d(TAG, "Dual band not supported with OWE, updating band index to 2GHz");
+ } else {
+ mBandIndex = BAND_BOTH_2G_5G;
+ }
+ } else
+ mBandIndex = validateSelection(config.getBand());
Log.d(TAG, "Updating band index to " + mBandIndex);
} else {
mWifiManager.setSoftApConfiguration(
new SoftApConfiguration.Builder(config).setBand(SoftApConfiguration.BAND_2GHZ)
.build());
mBandIndex = SoftApConfiguration.BAND_2GHZ;
- Log.d(TAG, "5Ghz not supported, updating band index to 2GHz");
+ Log.d(TAG, "5Ghz/6Ghz not supported, updating band index to 2GHz");
}
ListPreference preference =
(ListPreference) mPreference;
preference.setEntries(mBandSummaries);
preference.setEntryValues(mBandEntries);
- if (!is5GhzBandSupported()) {
+ if (!is5GhzBandSupported() && !is6GhzBandSupported()) {
preference.setEnabled(false);
preference.setSummary(R.string.wifi_ap_choose_2G);
} else {
- preference.setValue(Integer.toString(config.getBand()));
+ preference.setValue(Integer.toString(mBandIndex));
preference.setSummary(getConfigSummary());
}
}
@@ -80,8 +111,11 @@ public class WifiTetherApBandPreferenceController extends WifiTetherBasePreferen
switch (mBandIndex) {
case SoftApConfiguration.BAND_2GHZ:
return mBandSummaries[0];
- case SoftApConfiguration.BAND_5GHZ:
- return mBandSummaries[1];
+ case BAND_5GHZ:
+ case BAND_6GHZ:
+ case BAND_BOTH_2G_5G:
+ final ListPreference preference = (ListPreference) mPreference;
+ return mBandSummaries[preference.findIndexOfValue(String.valueOf(mBandIndex))];
default:
return mContext.getString(R.string.wifi_ap_prefer_5G);
}
@@ -95,6 +129,7 @@ public class WifiTetherApBandPreferenceController extends WifiTetherBasePreferen
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
+ syncBandSupportAndCountryCode();
mBandIndex = validateSelection(Integer.parseInt((String) newValue));
Log.d(TAG, "Band preference changed, updating band index to " + mBandIndex);
preference.setSummary(getConfigSummary());
@@ -106,11 +141,17 @@ public class WifiTetherApBandPreferenceController extends WifiTetherBasePreferen
// unsupported states:
// 1: BAND_5GHZ only - include 2GHZ since some of countries doesn't support 5G hotspot
// 2: no 5 GHZ support means we can't have BAND_5GHZ - default to 2GHZ
- if (SoftApConfiguration.BAND_5GHZ == band) {
+ // 3: no 6 GHZ support means we can't have AP_BAND_6GHZ - default to 2GHZ
+ if (band == BAND_5GHZ) {
if (!is5GhzBandSupported()) {
return SoftApConfiguration.BAND_2GHZ;
}
- return SoftApConfiguration.BAND_5GHZ | SoftApConfiguration.BAND_2GHZ;
+ // fallthrough to return BAND_5GHZ
+ } else if (band == BAND_6GHZ) {
+ if (!is6GhzBandSupported()) {
+ return SoftApConfiguration.BAND_2GHZ;
+ }
+ // fallthrough to return BAND_6GHZ
}
return band;
@@ -118,16 +159,55 @@ public class WifiTetherApBandPreferenceController extends WifiTetherBasePreferen
@VisibleForTesting
void updatePreferenceEntries() {
+ final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
Resources res = mContext.getResources();
- int entriesRes = R.array.wifi_ap_band;
- int summariesRes = R.array.wifi_ap_band_summary;
- mBandEntries = res.getStringArray(entriesRes);
- mBandSummaries = res.getStringArray(summariesRes);
+ ArrayList<String> bandEntries = new ArrayList<String>();
+ ArrayList<String> bandSummaries = new ArrayList<String>();
+ // Add 2GHz band
+ bandEntries.add(String.valueOf(SoftApConfiguration.BAND_2GHZ));
+ bandSummaries.add(mContext.getString(R.string.wifi_ap_choose_2G));
+ // Add 5GHz band
+ if (is5GhzBandSupported()) {
+ bandEntries.add(String.valueOf(BAND_5GHZ));
+ bandSummaries.add(mContext.getString(R.string.wifi_ap_prefer_5G));
+ }
+ // Add 6GHz band
+ if (is6GhzBandSupported()) {
+ bandEntries.add(String.valueOf(BAND_6GHZ));
+ bandSummaries.add(mContext.getString(R.string.wifi_ap_prefer_6G));
+ }
+ // Add Dual AP bands
+ if (is5GhzBandSupported()
+ && (mWifiManager.isBridgedApConcurrencySupported() || isVendorLegacyDualBandSupported())
+ && (config != null) && (config.getSecurityType() != SoftApConfiguration.SECURITY_TYPE_OWE)) {
+ /* isConcurrentBandSupported indicates Concurrent band support
+ * for HW_SUPPORTED_FEATURES.*/
+ if (mWifiManager.isConcurrentBandSupported()) {
+ bandEntries.add(String.valueOf(BAND_BOTH_2G_5G));
+ bandSummaries.add(mContext.getString(R.string.wifi_ap_choose_vendor_dual_band));
+ }
+ }
+
+ mBandEntries = bandEntries.toArray(new String[bandEntries.size()]);
+ mBandSummaries = bandSummaries.toArray(new String[bandSummaries.size()]);
+ }
+
+ // This is used to reduce IPC calls to framework.
+ private void syncBandSupportAndCountryCode() {
+ m5GHzSupported = mWifiManager.is5GHzBandSupported();
+ m6GHzSupported = mWifiManager.is6GHzBandSupported();
+ mCountryCode = mWifiManager.getCountryCode();
}
private boolean is5GhzBandSupported() {
- final String countryCode = mWifiManager.getCountryCode();
- if (!mWifiManager.is5GHzBandSupported() || countryCode == null) {
+ if (!m5GHzSupported || mCountryCode == null) {
+ return false;
+ }
+ return true;
+ }
+
+ private boolean is6GhzBandSupported() {
+ if (!m6GHzSupported || mCountryCode == null) {
return false;
}
return true;
@@ -136,4 +216,9 @@ public class WifiTetherApBandPreferenceController extends WifiTetherBasePreferen
public int getBandIndex() {
return mBandIndex;
}
+
+ private boolean isVendorLegacyDualBandSupported() {
+ return mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_wifi_dual_sap_mode_enabled);
+ }
}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherAutoOffPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherAutoOffPreferenceController.java
index b54a80f6b4..8ada0b3b32 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherAutoOffPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherAutoOffPreferenceController.java
@@ -22,13 +22,17 @@ import android.net.wifi.WifiManager;
import androidx.preference.Preference;
import androidx.preference.SwitchPreference;
+import androidx.preference.PreferenceScreen;
import com.android.settings.core.BasePreferenceController;
+import android.util.Log;
public class WifiTetherAutoOffPreferenceController extends BasePreferenceController implements
Preference.OnPreferenceChangeListener {
private final WifiManager mWifiManager;
+ private String TAG = "WifiTetherAutoOffPreferenceController";
+ private SwitchPreference mPreference = null;
public WifiTetherAutoOffPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
@@ -41,6 +45,19 @@ public class WifiTetherAutoOffPreferenceController extends BasePreferenceControl
}
@Override
+ public void displayPreference(PreferenceScreen scr) {
+ super.displayPreference(scr);
+ mPreference = scr.findPreference(getPreferenceKey());
+ }
+
+ public void updateDisplay() {
+ if(mPreference != null)
+ updateState(mPreference);
+ else
+ Log.e(TAG, "updateDisplay Failed, cannot find switch preference");
+ }
+
+ @Override
public void updateState(Preference preference) {
SoftApConfiguration softApConfiguration = mWifiManager.getSoftApConfiguration();
final boolean settingsOn = softApConfiguration.isAutoShutdownEnabled();
diff --git a/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceController.java
deleted file mode 100644
index a1a10ea643..0000000000
--- a/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceController.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.wifi.tether;
-
-import android.content.Context;
-import android.net.wifi.SoftApConfiguration;
-import android.util.Log;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.SwitchPreference;
-
-import com.android.settings.R;
-
-/**
- * This controller helps to manage the state of maximize compatibility switch preference.
- */
-public class WifiTetherMaximizeCompatibilityPreferenceController extends
- WifiTetherBasePreferenceController {
-
- private static final String TAG = "WifiTetherMaximizeCompatibilityPref";
- public static final String PREF_KEY = "wifi_tether_maximize_compatibility";
-
- private boolean mIsChecked;
-
- public WifiTetherMaximizeCompatibilityPreferenceController(Context context,
- WifiTetherBasePreferenceController.OnTetherConfigUpdateListener listener) {
- super(context, listener);
- mIsChecked = isMaximizeCompatibilityEnabled();
- }
-
- @Override
- public String getPreferenceKey() {
- return PREF_KEY;
- }
-
- @Override
- public void updateDisplay() {
- if (mPreference == null) {
- return;
- }
- mPreference.setEnabled(is5GhzBandSupported());
- ((SwitchPreference) mPreference).setChecked(mIsChecked);
- mPreference.setSummary(mWifiManager.isBridgedApConcurrencySupported()
- ? R.string.wifi_hotspot_maximize_compatibility_dual_ap_summary
- : R.string.wifi_hotspot_maximize_compatibility_single_ap_summary);
- }
-
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- mIsChecked = (Boolean) newValue;
- if (mListener != null) {
- mListener.onTetherConfigUpdated(this);
- }
- return true;
- }
-
- private boolean is5GhzBandSupported() {
- if (mWifiManager == null) {
- return false;
- }
- if (!mWifiManager.is5GHzBandSupported() || mWifiManager.getCountryCode() == null) {
- return false;
- }
- return true;
- }
-
- @VisibleForTesting
- boolean isMaximizeCompatibilityEnabled() {
- if (mWifiManager == null) {
- return false;
- }
- final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
- if (config == null) {
- return false;
- }
- if (mWifiManager.isBridgedApConcurrencySupported()) {
- final boolean isEnabled = config.isBridgedModeOpportunisticShutdownEnabled();
- Log.d(TAG, "isBridgedModeOpportunisticShutdownEnabled:" + isEnabled);
- // Because the return value defined by the Wi-Fi framework API is opposite to the UI.
- // Compatibility on: isBridgedModeOpportunisticShutdownEnabled() = false
- // Compatibility off: isBridgedModeOpportunisticShutdownEnabled() = true
- // Need to return the reverse value.
- return !isEnabled;
- }
-
- // If the BridgedAp Concurrency is not supported in early Pixel devices (e.g. Pixel 2~5),
- // show toggle on when band is 2.4G only.
- final int band = config.getBand();
- Log.d(TAG, "getBand:" + band);
- return band == SoftApConfiguration.BAND_2GHZ;
- }
-
- /**
- * Setup the Maximize Compatibility setting to the SoftAp Configuration
- *
- * @param builder The builder to build the SoftApConfiguration.
- */
- public void setupMaximizeCompatibility(SoftApConfiguration.Builder builder) {
- if (builder == null) {
- return;
- }
- final boolean enabled = mIsChecked;
- if (mWifiManager.isBridgedApConcurrencySupported()) {
- int[] bands = {
- SoftApConfiguration.BAND_2GHZ,
- SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ};
- builder.setBands(bands);
- Log.d(TAG, "setBridgedModeOpportunisticShutdownEnabled:" + enabled);
- // Because the defined value by the Wi-Fi framework API is opposite to the UI.
- // Compatibility on: setBridgedModeOpportunisticShutdownEnabled(false)
- // Compatibility off: setBridgedModeOpportunisticShutdownEnabled(true)
- // Need to set the reverse value.
- builder.setBridgedModeOpportunisticShutdownEnabled(!enabled);
- } else {
- int band = enabled
- ? SoftApConfiguration.BAND_2GHZ
- : SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ;
- Log.d(TAG, "setBand:" + band);
- builder.setBand(band);
- }
- }
-}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
index 14766f9ee4..ec70f97b52 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherPasswordPreferenceController.java
@@ -72,7 +72,7 @@ public class WifiTetherPasswordPreferenceController extends WifiTetherBasePrefer
@Override
public void updateDisplay() {
final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
- if (config.getSecurityType() != SoftApConfiguration.SECURITY_TYPE_OPEN
+ if (!isNoPasswordSecurityrType(config.getSecurityType())
&& TextUtils.isEmpty(config.getPassphrase())) {
mPassword = generateRandomPassword();
} else {
@@ -107,7 +107,7 @@ public class WifiTetherPasswordPreferenceController extends WifiTetherBasePrefer
*/
public String getPasswordValidated(int securityType) {
// don't actually overwrite unless we get a new config in case it was accidentally toggled.
- if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN) {
+ if (isNoPasswordSecurityrType(securityType)) {
return "";
} else if (!WifiUtils.isHotspotPasswordValid(mPassword, securityType)) {
mPassword = generateRandomPassword();
@@ -124,7 +124,7 @@ public class WifiTetherPasswordPreferenceController extends WifiTetherBasePrefer
*/
public void setSecurityType(int securityType) {
mSecurityType = securityType;
- mPreference.setVisible(securityType != SoftApConfiguration.SECURITY_TYPE_OPEN);
+ mPreference.setVisible(!isNoPasswordSecurityrType(securityType));
}
@Override
@@ -151,4 +151,9 @@ public class WifiTetherPasswordPreferenceController extends WifiTetherBasePrefer
pref.setVisible(false);
}
}
+
+ private boolean isNoPasswordSecurityrType(int securityType) {
+ return (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN
+ || securityType == SoftApConfiguration.SECURITY_TYPE_OWE);
+ }
}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
index 70b6a45eb5..70ac155974 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherPreferenceController.java
@@ -130,10 +130,15 @@ public class WifiTetherPreferenceController extends AbstractPreferenceController
public void onConnectedClientsChanged(List<WifiClient> clients) {
if (mPreference != null
&& mSoftApState == WifiManager.WIFI_AP_STATE_ENABLED) {
+ String extendWifiSummary = "";
+ if (mWifiManager.isExtendingWifi()) {
+ extendWifiSummary = "Extending Wifi-Coverage: ";
+ }
+
// Only show the number of clients when state is on
- mPreference.setSummary(mContext.getResources().getQuantityString(
- R.plurals.wifi_tether_connected_summary, clients.size(),
- clients.size()));
+ mPreference.setSummary(extendWifiSummary + mContext.getResources()
+ .getQuantityString(R.plurals.wifi_tether_connected_summary,
+ clients.size(), clients.size()));
}
}
});
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java b/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java
index acb8206249..0c209d491a 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSecurityPreferenceController.java
@@ -48,18 +48,23 @@ public class WifiTetherSecurityPreferenceController extends WifiTetherBasePrefer
private int mSecurityValue;
@VisibleForTesting
boolean mIsWpa3Supported = true;
+ boolean mIsOweSapSupported = true;
+ boolean mIsDualSapSupported = false;
+ private String[] securityNames;
+ private String[] securityValues;
public WifiTetherSecurityPreferenceController(Context context,
OnTetherConfigUpdateListener listener) {
super(context, listener);
- final String[] securityNames = mContext.getResources().getStringArray(
+ securityNames = mContext.getResources().getStringArray(
R.array.wifi_tether_security);
- final String[] securityValues = mContext.getResources().getStringArray(
+ securityValues = mContext.getResources().getStringArray(
R.array.wifi_tether_security_values);
for (int i = 0; i < securityNames.length; i++) {
mSecurityMap.put(Integer.parseInt(securityValues[i]), securityNames[i]);
}
mWifiManager.registerSoftApCallback(context.getMainExecutor(), this);
+ mIsDualSapSupported = mWifiManager.isBridgedApConcurrencySupported();
}
@Override
@@ -78,17 +83,41 @@ public class WifiTetherSecurityPreferenceController extends WifiTetherBasePrefer
return;
}
final ListPreference preference = (ListPreference) mPreference;
- // If the device is not support WPA3 then remove the WPA3 options.
+ final SoftApConfiguration config = mWifiManager.getSoftApConfiguration();
+ int defaultSecurityType = SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
+
+ for (int i = 0; i < securityNames.length; i++) {
+ mSecurityMap.put(Integer.parseInt(securityValues[i]), securityNames[i]);
+ }
+
+ preference.setEntries(mSecurityMap.values().stream().toArray(CharSequence[]::new));
+ preference.setEntryValues(mSecurityMap.keySet().stream().map(i -> Integer.toString(i))
+ .toArray(CharSequence[]::new));
+
+ if (config.getBand() == (SoftApConfiguration.BAND_6GHZ | SoftApConfiguration.BAND_2GHZ)
+ && mSecurityMap.keySet().removeIf(
+ key -> key < SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)) {
+ preference.setEntries(mSecurityMap.values().stream().toArray(CharSequence[]::new));
+ preference.setEntryValues(mSecurityMap.keySet().stream().map(i -> Integer.toString(i))
+ .toArray(CharSequence[]::new));
+ defaultSecurityType = SoftApConfiguration.SECURITY_TYPE_WPA3_SAE;
+ }
+ // If the device does not support WPA3 /OWE then remove the WPA3 /OWE options.
if (!mIsWpa3Supported && mSecurityMap.keySet()
.removeIf(key -> key > SoftApConfiguration.SECURITY_TYPE_WPA2_PSK)) {
preference.setEntries(mSecurityMap.values().stream().toArray(CharSequence[]::new));
- preference.setEntryValues(mSecurityMap.keySet().stream().map(Integer::toBinaryString)
+ preference.setEntryValues(mSecurityMap.keySet().stream().map(i -> Integer.toString(i))
+ .toArray(CharSequence[]::new));
+ } else if (!(mIsDualSapSupported && mIsOweSapSupported) && mSecurityMap.keySet()
+ .removeIf(key -> key > SoftApConfiguration.SECURITY_TYPE_WPA3_SAE)) {
+ preference.setEntries(mSecurityMap.values().stream().toArray(CharSequence[]::new));
+ preference.setEntryValues(mSecurityMap.keySet().stream().map(i -> Integer.toString(i))
.toArray(CharSequence[]::new));
}
final int securityType = mWifiManager.getSoftApConfiguration().getSecurityType();
mSecurityValue = mSecurityMap.get(securityType) != null
- ? securityType : SoftApConfiguration.SECURITY_TYPE_WPA2_PSK;
+ ? securityType : defaultSecurityType;
preference.setSummary(mSecurityMap.get(mSecurityValue));
preference.setValue(String.valueOf(mSecurityValue));
@@ -111,8 +140,17 @@ public class WifiTetherSecurityPreferenceController extends WifiTetherBasePrefer
if (!isWpa3Supported) {
Log.i(PREF_KEY, "WPA3 SAE is not supported on this device");
}
- if (mIsWpa3Supported != isWpa3Supported) {
+
+ final boolean isOweSupported =
+ softApCapability.areFeaturesSupported(SoftApCapability.SOFTAP_FEATURE_WPA3_OWE);
+ if (!isOweSupported) {
+ Log.i(PREF_KEY, "OWE not supported.");
+ }
+
+ if (mIsWpa3Supported != isWpa3Supported
+ || mIsOweSapSupported != isOweSupported) {
mIsWpa3Supported = isWpa3Supported;
+ mIsOweSapSupported = isOweSupported;
updateDisplay();
}
mWifiManager.unregisterSoftApCallback(this);
@@ -121,4 +159,8 @@ public class WifiTetherSecurityPreferenceController extends WifiTetherBasePrefer
public int getSecurityType() {
return mSecurityValue;
}
+
+ public boolean isOweDualSapSupported() {
+ return mIsDualSapSupported && mIsOweSapSupported;
+ }
}
diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
index 23601fac5d..02e0cd7025 100644
--- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java
+++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java
@@ -18,6 +18,7 @@ package com.android.settings.wifi.tether;
import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_CHANGED_ACTION;
+import static com.android.settings.wifi.tether.WifiTetherApBandPreferenceController.BAND_BOTH_2G_5G;
import android.app.settings.SettingsEnums;
import android.content.BroadcastReceiver;
@@ -54,6 +55,9 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
private static final String TAG = "WifiTetherSettings";
private static final IntentFilter TETHER_STATE_CHANGE_FILTER;
private static final String KEY_WIFI_TETHER_SCREEN = "wifi_tether_settings_screen";
+ private static final int EXPANDED_CHILD_COUNT_WITH_SECURITY_NON = 3;
+ private static boolean mWasApBand6GHzSelected = false;
+ private static final int BAND_6GHZ = SoftApConfiguration.BAND_6GHZ | SoftApConfiguration.BAND_2GHZ;
@VisibleForTesting
static final String KEY_WIFI_TETHER_NETWORK_NAME = "wifi_tether_network_name";
@@ -62,18 +66,18 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
@VisibleForTesting
static final String KEY_WIFI_TETHER_AUTO_OFF = "wifi_tether_auto_turn_off";
@VisibleForTesting
- static final String KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY =
- WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY;
+ static final String KEY_WIFI_TETHER_NETWORK_AP_BAND = "wifi_tether_network_ap_band";
private WifiTetherSwitchBarController mSwitchBarController;
private WifiTetherSSIDPreferenceController mSSIDPreferenceController;
private WifiTetherPasswordPreferenceController mPasswordPreferenceController;
+ private WifiTetherApBandPreferenceController mApBandPreferenceController;
private WifiTetherSecurityPreferenceController mSecurityPreferenceController;
- private WifiTetherMaximizeCompatibilityPreferenceController mMaxCompatibilityPrefController;
private WifiManager mWifiManager;
private boolean mRestartWifiApAfterConfigChange;
private boolean mUnavailable;
+ private boolean wasApBandPrefUpdated = false;
@VisibleForTesting
TetherChangeReceiver mTetherChangeReceiver;
@@ -115,8 +119,7 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
mSSIDPreferenceController = use(WifiTetherSSIDPreferenceController.class);
mSecurityPreferenceController = use(WifiTetherSecurityPreferenceController.class);
mPasswordPreferenceController = use(WifiTetherPasswordPreferenceController.class);
- mMaxCompatibilityPrefController =
- use(WifiTetherMaximizeCompatibilityPreferenceController.class);
+ mApBandPreferenceController = use(WifiTetherApBandPreferenceController.class);
}
@Override
@@ -180,15 +183,16 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
controllers.add(new WifiTetherSSIDPreferenceController(context, listener));
controllers.add(new WifiTetherSecurityPreferenceController(context, listener));
controllers.add(new WifiTetherPasswordPreferenceController(context, listener));
+ controllers.add(new WifiTetherApBandPreferenceController(context, listener));
controllers.add(
new WifiTetherAutoOffPreferenceController(context, KEY_WIFI_TETHER_AUTO_OFF));
- controllers.add(new WifiTetherMaximizeCompatibilityPreferenceController(context, listener));
+
return controllers;
}
@Override
public void onTetherConfigUpdated(AbstractPreferenceController context) {
- final SoftApConfiguration config = buildNewConfig();
+ SoftApConfiguration config = buildNewConfig();
mPasswordPreferenceController.setSecurityType(config.getSecurityType());
/**
@@ -203,18 +207,59 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
mSwitchBarController.stopTether();
}
mWifiManager.setSoftApConfiguration(config);
+ use(WifiTetherAutoOffPreferenceController.class).updateDisplay();
+
+ if (mSecurityPreferenceController.isOweDualSapSupported()) {
+ if ((config.getSecurityType() == SoftApConfiguration.SECURITY_TYPE_OWE)
+ && (mApBandPreferenceController.getBandIndex() == BAND_BOTH_2G_5G)) {
+ mApBandPreferenceController.updatePreferenceEntries();
+ mApBandPreferenceController.updateDisplay();
+ wasApBandPrefUpdated = true;
+ } else if (wasApBandPrefUpdated
+ && config.getSecurityType() != SoftApConfiguration.SECURITY_TYPE_OWE) {
+ mApBandPreferenceController.updatePreferenceEntries();
+ mApBandPreferenceController.updateDisplay();
+ wasApBandPrefUpdated = false;
+ }
+ }
+
+ if (mApBandPreferenceController.getBandIndex() == BAND_6GHZ
+ && (mWasApBand6GHzSelected == false)) {
+ mSecurityPreferenceController.updateDisplay();
+ mWasApBand6GHzSelected = true;
+ config = buildNewConfig();
+ mWifiManager.setSoftApConfiguration(config);
+ } else if (mApBandPreferenceController.getBandIndex() != BAND_6GHZ
+ &&(mWasApBand6GHzSelected == true)) {
+ mSecurityPreferenceController.updateDisplay();
+ mWasApBand6GHzSelected = false;
+ }
}
private SoftApConfiguration buildNewConfig() {
final SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder();
final int securityType = mSecurityPreferenceController.getSecurityType();
configBuilder.setSsid(mSSIDPreferenceController.getSSID());
- if (securityType != SoftApConfiguration.SECURITY_TYPE_OPEN) {
+ if (securityType == SoftApConfiguration.SECURITY_TYPE_OPEN
+ || securityType == SoftApConfiguration.SECURITY_TYPE_OWE) {
+ configBuilder.setPassphrase(null, securityType);
+ } else {
configBuilder.setPassphrase(
mPasswordPreferenceController.getPasswordValidated(securityType),
securityType);
}
- mMaxCompatibilityPrefController.setupMaximizeCompatibility(configBuilder);
+ if (mApBandPreferenceController.getBandIndex() == BAND_BOTH_2G_5G) {
+ // Fallback to 2G band if user selected OWE+Dual band
+ if (securityType == SoftApConfiguration.SECURITY_TYPE_OWE) {
+ configBuilder.setBand(SoftApConfiguration.BAND_2GHZ);
+ } else {
+ int[] dualBands = new int[] {
+ SoftApConfiguration.BAND_2GHZ, SoftApConfiguration.BAND_5GHZ};
+ configBuilder.setBands(dualBands);
+ }
+ } else {
+ configBuilder.setBand(mApBandPreferenceController.getBandIndex());
+ }
return configBuilder.build();
}
@@ -224,10 +269,14 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
}
private void updateDisplayWithNewConfig() {
- use(WifiTetherSSIDPreferenceController.class).updateDisplay();
- use(WifiTetherSecurityPreferenceController.class).updateDisplay();
- use(WifiTetherPasswordPreferenceController.class).updateDisplay();
- use(WifiTetherMaximizeCompatibilityPreferenceController.class).updateDisplay();
+ use(WifiTetherSSIDPreferenceController.class)
+ .updateDisplay();
+ use(WifiTetherSecurityPreferenceController.class)
+ .updateDisplay();
+ use(WifiTetherPasswordPreferenceController.class)
+ .updateDisplay();
+ use(WifiTetherApBandPreferenceController.class)
+ .updateDisplay();
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
@@ -241,7 +290,7 @@ public class WifiTetherSettings extends RestrictedDashboardFragment
keys.add(KEY_WIFI_TETHER_NETWORK_NAME);
keys.add(KEY_WIFI_TETHER_NETWORK_PASSWORD);
keys.add(KEY_WIFI_TETHER_AUTO_OFF);
- keys.add(KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
+ keys.add(KEY_WIFI_TETHER_NETWORK_AP_BAND);
}
// Remove duplicate
diff --git a/tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceControllerTest.java
index 7dd2906941..0f01e00a3f 100644
--- a/tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/development/bluetooth/BluetoothCodecDialogPreferenceControllerTest.java
@@ -19,6 +19,7 @@ package com.android.settings.development.bluetooth;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -108,6 +109,8 @@ public class BluetoothCodecDialogPreferenceControllerTest {
BluetoothCodecConfig[] mCodecConfigs = {mCodecConfigAAC, mCodecConfigSBC};
mCodecStatus = new BluetoothCodecStatus(mCodecConfigSBC, null, mCodecConfigs);
when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus);
+ when(mBluetoothA2dp.isOptionalCodecsEnabled(mActiveDevice)).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
mController.onBluetoothServiceConnected(mBluetoothA2dp);
mController.writeConfigurationValues(0);
@@ -172,4 +175,37 @@ public class BluetoothCodecDialogPreferenceControllerTest {
verify(mCallback).onBluetoothCodecChanged();
}
+
+ @Test
+ public void onHDAudioEnabled_optionalCodecEnabled_setsCodecTypeAsAAC() {
+ BluetoothCodecConfig[] mCodecConfigs = {mCodecConfigAAC, mCodecConfigSBC};
+ mCodecStatus = new BluetoothCodecStatus(mCodecConfigAAC,
+ /* codecsLocalCapabilities= */ null,
+ mCodecConfigs);
+ when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus);
+ when(mBluetoothA2dp.isOptionalCodecsEnabled(mActiveDevice)).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED);
+ mController.onBluetoothServiceConnected(mBluetoothA2dp);
+
+ mController.onHDAudioEnabled(/* enabled= */ true);
+
+ verify(mBluetoothA2dpConfigStore, atLeastOnce()).setCodecType(
+ eq(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC));
+ }
+ @Test
+ public void onHDAudioEnabled_optionalCodecDisabled_setsCodecTypeAsSBC() {
+ BluetoothCodecConfig[] mCodecConfigs = {mCodecConfigAAC, mCodecConfigSBC};
+ mCodecStatus = new BluetoothCodecStatus(mCodecConfigAAC,
+ /* codecsLocalCapabilities= */ null,
+ mCodecConfigs);
+ when(mBluetoothA2dp.getCodecStatus(mActiveDevice)).thenReturn(mCodecStatus);
+ when(mBluetoothA2dp.isOptionalCodecsEnabled(mActiveDevice)).thenReturn(
+ BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED);
+ mController.onBluetoothServiceConnected(mBluetoothA2dp);
+
+ mController.onHDAudioEnabled(/* enabled= */ false);
+
+ verify(mBluetoothA2dpConfigStore, atLeastOnce()).setCodecType(
+ eq(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC));
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java
index ff0f25c338..edb2c3c477 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/ConvertUtilsTest.java
@@ -353,6 +353,38 @@ public final class ConvertUtilsTest {
}
@Test
+ public void testGetIndexedUsageMap_hideBackgroundUsageTime_returnsExpectedResult() {
+ final long[] batteryHistoryKeys = new long[] {101L, 102L, 103L};
+ final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap = new HashMap<>();
+ final BatteryHistEntry fakeEntry = createBatteryHistEntry(
+ ConvertUtils.FAKE_PACKAGE_NAME, "fake_label", 0, 0L, 0L, 0L);
+ // Adds the index = 0 data.
+ Map<String, BatteryHistEntry> entryMap = new HashMap<>();
+ entryMap.put(fakeEntry.getKey(), fakeEntry);
+ batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[0]), entryMap);
+ // Adds the index = 1 data.
+ entryMap = new HashMap<>();
+ entryMap.put(fakeEntry.getKey(), fakeEntry);
+ batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[1]), entryMap);
+ // Adds the index = 2 data.
+ entryMap = new HashMap<>();
+ final BatteryHistEntry entry = createBatteryHistEntry(
+ "package3", "label3", 500, 5L, 3600000L, 7200000L);
+ entryMap.put(entry.getKey(), entry);
+ batteryHistoryMap.put(Long.valueOf(batteryHistoryKeys[2]), entryMap);
+ when(mPowerUsageFeatureProvider.getHideBackgroundUsageTimeList(mContext))
+ .thenReturn(Arrays.asList((CharSequence) "package3"));
+
+ final Map<Integer, List<BatteryDiffEntry>> purgedResultMap =
+ ConvertUtils.getIndexedUsageMap(
+ mContext, /*timeSlotSize=*/ 1, batteryHistoryKeys, batteryHistoryMap,
+ /*purgeLowPercentageAndFakeData=*/ true);
+
+ final BatteryDiffEntry resultEntry = purgedResultMap.get(0).get(0);
+ assertThat(resultEntry.mBackgroundUsageTimeInMs).isEqualTo(0);
+ }
+
+ @Test
public void getLocale_nullContext_returnDefaultLocale() {
assertThat(ConvertUtils.getLocale(/*context=*/ null))
.isEqualTo(Locale.getDefault());
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/WifiSettingsTest.java
index 5f2f5647c5..def4169697 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiSettingsTest.java
@@ -277,6 +277,8 @@ public class WifiSettingsTest {
@Test
public void onWifiEntriesChanged_shouldChangeNextButtonState() {
+ final FragmentActivity activity = mock(FragmentActivity.class);
+ doReturn(activity).when(mWifiSettings).getActivity();
mWifiSettings.onWifiEntriesChanged();
verify(mWifiSettings).changeNextButtonState(anyBoolean());
diff --git a/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java
index 796cdef434..78e696d641 100644
--- a/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/p2p/WifiP2pSettingsTest.java
@@ -39,7 +39,7 @@ import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Bundle;
import android.view.MenuItem;
-
+import android.view.LayoutInflater;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
@@ -110,30 +110,30 @@ public class WifiP2pSettingsTest {
}
@Test
- public void onActivityCreate_withNullBundle_canNotGetValue() {
- mFragment.onActivityCreated(null);
+ public void onCreateView_withNullBundle_canNotGetValue() {
+ mFragment.onCreateView(LayoutInflater.from(mContext), null, null);
assertThat(mFragment.mSelectedWifiPeer).isNull();
}
@Test
- public void onActivityCreate_withDeviceName_shouldGetDeviceName() {
+ public void onCreateView_withDeviceName_shouldGetDeviceName() {
final String fakeDeviceName = "fakename";
final Bundle bundle = new Bundle();
bundle.putString(WifiP2pSettings.SAVE_DEVICE_NAME, fakeDeviceName);
- mFragment.onActivityCreated(bundle);
+ mFragment.onCreateView(LayoutInflater.from(mContext), null, bundle);
assertThat(mFragment.mSavedDeviceName).isEqualTo(fakeDeviceName);
}
@Test
- public void onActivityCreate_withGroupName_shouldGetGroupName() {
+ public void onCreateView_withGroupName_shouldGetGroupName() {
final String fakeGroupName = "fakegroup";
final Bundle bundle = new Bundle();
bundle.putString(WifiP2pSettings.SAVE_SELECTED_GROUP, fakeGroupName);
- mFragment.onActivityCreated(bundle);
+ mFragment.onCreateView(LayoutInflater.from(mContext), null, bundle);
assertThat(mFragment.mSelectedGroupName).isEqualTo(fakeGroupName);
assertThat(mFragment.mSavedDeviceName).isNull();
@@ -279,7 +279,7 @@ public class WifiP2pSettingsTest {
final String fakeDeviceName = "fakeName";
final Bundle bundle = new Bundle();
bundle.putString(WifiP2pSettings.SAVE_DEVICE_NAME, fakeDeviceName);
- mFragment.onActivityCreated(bundle);
+ mFragment.onCreateView(LayoutInflater.from(mContext), null, bundle);
final Dialog dialog = mFragment.onCreateDialog(WifiP2pSettings.DIALOG_RENAME);
mFragment.mRenameListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
@@ -292,7 +292,8 @@ public class WifiP2pSettingsTest {
final String fakeDeviceName = "wrongName***";
final Bundle bundle = new Bundle();
bundle.putString(WifiP2pSettings.SAVE_DEVICE_NAME, fakeDeviceName);
- mFragment.onActivityCreated(bundle);
+ mFragment.onCreateView(LayoutInflater.from(mContext), null, bundle);
+
final Dialog dialog = mFragment.onCreateDialog(WifiP2pSettings.DIALOG_RENAME);
mFragment.mRenameListener.onClick(dialog, DialogInterface.BUTTON_POSITIVE);
@@ -394,7 +395,7 @@ public class WifiP2pSettingsTest {
final String fakeDeviceName = "fakeName";
final Bundle createBundle = new Bundle();
createBundle.putString(WifiP2pSettings.SAVE_DEVICE_NAME, fakeDeviceName);
- mFragment.onActivityCreated(createBundle);
+ mFragment.onCreateView(LayoutInflater.from(mContext), null, createBundle);
final Bundle outBundle = new Bundle();
final Dialog dialog = mFragment.onCreateDialog(WifiP2pSettings.DIALOG_RENAME);
@@ -430,7 +431,7 @@ public class WifiP2pSettingsTest {
doReturn(groupList).when(wifiP2pGroupList).getGroupList();
final Bundle bundle = new Bundle();
bundle.putString(WifiP2pSettings.SAVE_SELECTED_GROUP, fakeGroupName);
- mFragment.onActivityCreated(bundle);
+ mFragment.onCreateView(LayoutInflater.from(mContext), null, bundle);
mFragment.onPersistentGroupInfoAvailable(wifiP2pGroupList);
@@ -503,20 +504,20 @@ public class WifiP2pSettingsTest {
}
@Test
- public void onActivityCreate_withNullP2pManager_shouldGetP2pManagerAgain() {
- mFragment.mChannel = null; // Reset channel to re-test onActivityCreated flow
+ public void onCreateView_withNullP2pManager_shouldGetP2pManagerAgain() {
+ mFragment.mChannel = null; // Reset channel to re-test onCreateView flow
mFragment.mWifiP2pManager = null;
- mFragment.onActivityCreated(new Bundle());
+ mFragment.onCreateView(LayoutInflater.from(mContext), null, new Bundle());
assertThat(mFragment.mWifiP2pManager).isNotNull();
}
@Test
- public void onActivityCreate_withNullChannel_shouldSetP2pManagerNull() {
+ public void onCreateView_withNullChannel_shouldSetP2pManagerNull() {
doReturn(null).when(mWifiP2pManager).initialize(any(), any(), any());
- mFragment.mChannel = null; // Reset channel to re-test onActivityCreated flow
- mFragment.onActivityCreated(new Bundle());
+ mFragment.mChannel = null; // Reset channel to re-test onCreateView flow
+ mFragment.onCreateView(LayoutInflater.from(mContext), null, new Bundle());
assertThat(mFragment.mWifiP2pManager).isNull();
}
diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
index 2ecc7d26d5..a241296191 100644
--- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java
@@ -101,7 +101,7 @@ public class WifiTetherSettingsTest {
assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
- assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
+ assertThat(niks).doesNotContain(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_AP_BAND);
}
@Test
@@ -115,7 +115,7 @@ public class WifiTetherSettingsTest {
assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_NAME);
assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_PASSWORD);
assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_AUTO_OFF);
- assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_MAXIMIZE_COMPATIBILITY);
+ assertThat(niks).contains(WifiTetherSettings.KEY_WIFI_TETHER_NETWORK_AP_BAND);
}
@Test
diff --git a/tests/unit/src/com/android/settings/network/NetworkProviderCallsSmsFragmentTest.java b/tests/unit/src/com/android/settings/network/NetworkProviderCallsSmsFragmentTest.java
index d00e2dd891..91257c1d0c 100644
--- a/tests/unit/src/com/android/settings/network/NetworkProviderCallsSmsFragmentTest.java
+++ b/tests/unit/src/com/android/settings/network/NetworkProviderCallsSmsFragmentTest.java
@@ -22,12 +22,14 @@ import static org.mockito.Mockito.spy;
import android.content.Context;
import android.os.Looper;
+import android.util.FeatureFlagUtils;
import androidx.test.annotation.UiThreadTest;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
@@ -51,6 +53,7 @@ public class NetworkProviderCallsSmsFragmentTest {
}
}
+ @Ignore
@Test
@UiThreadTest
public void isPageSearchEnabled_shouldIncludeFragmentXml() {
diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java
index 8687e5ada6..20821a0f2b 100644
--- a/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java
+++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceHelperTest.java
@@ -224,8 +224,9 @@ public class ProviderModelSliceHelperTest {
public void getMobileDrawable_noCarrierData_getMobileDrawable() throws Throwable {
mockConnections(false, ServiceState.STATE_OUT_OF_SERVICE, "",
false, true);
- when(mConnectivityManager.getActiveNetwork()).thenReturn(null);
Drawable expectDrawable = mock(Drawable.class);
+ when(mConnectivityManager.getActiveNetwork()).thenReturn(null);
+ when(mTelephonyManager.isDataEnabled()).thenReturn(false);
assertThat(mProviderModelSliceHelper.getMobileDrawable(expectDrawable)).isEqualTo(
expectDrawable);
@@ -236,8 +237,9 @@ public class ProviderModelSliceHelperTest {
throws Throwable {
mockConnections(true, ServiceState.STATE_IN_SERVICE, "", true,
true);
- addNetworkTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
Drawable drawable = mock(Drawable.class);
+ addNetworkTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ when(mTelephonyManager.isDataEnabled()).thenReturn(true);
assertThat(mProviderModelSliceHelper.getMobileDrawable(drawable)).isEqualTo(
mDrawableWithSignalStrength);
@@ -252,6 +254,7 @@ public class ProviderModelSliceHelperTest {
true);
Drawable drawable = mock(Drawable.class);
addNetworkTransportType(NetworkCapabilities.TRANSPORT_WIFI);
+ when(mTelephonyManager.isDataEnabled()).thenReturn(true);
assertThat(mProviderModelSliceHelper.getMobileDrawable(drawable)).isEqualTo(
mDrawableWithSignalStrength);
diff --git a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
index 66247d3623..44643decbb 100644
--- a/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
+++ b/tests/unit/src/com/android/settings/network/ProviderModelSliceTest.java
@@ -65,6 +65,7 @@ import com.android.wifitrackerlib.WifiEntry;
import com.android.wifitrackerlib.WifiPickerTracker;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -485,6 +486,7 @@ public class ProviderModelSliceTest {
verify(mMockAlertDialog, never()).show();
}
+ @Ignore
@Test
public void doCarrierNetworkAction_toggleActionSetDataEnabled_setCarrierNetworkEnabledTrue() {
mMockProviderModelSlice.doCarrierNetworkAction(true /* isToggleAction */,
@@ -493,6 +495,7 @@ public class ProviderModelSliceTest {
verify(mMockNetworkProviderWorker).setCarrierNetworkEnabledIfNeeded(true, SUB_ID);
}
+ @Ignore
@Test
public void doCarrierNetworkAction_toggleActionSetDataDisabled_setCarrierNetworkEnabledFalse() {
mMockProviderModelSlice.doCarrierNetworkAction(true /* isToggleAction */,
@@ -501,6 +504,7 @@ public class ProviderModelSliceTest {
verify(mMockNetworkProviderWorker).setCarrierNetworkEnabledIfNeeded(false, SUB_ID);
}
+ @Ignore
@Test
public void doCarrierNetworkAction_primaryActionAndDataEnabled_connectCarrierNetwork() {
mMockProviderModelSlice.doCarrierNetworkAction(false /* isToggleAction */,
diff --git a/tests/unit/src/com/android/settings/network/telephony/NetworkScanHelperTest.java b/tests/unit/src/com/android/settings/network/telephony/NetworkScanHelperTest.java
index f046c9a6f2..a8acbe5348 100644
--- a/tests/unit/src/com/android/settings/network/telephony/NetworkScanHelperTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/NetworkScanHelperTest.java
@@ -92,7 +92,7 @@ public class NetworkScanHelperTest {
mNetworkScanExecutor = Executors.newFixedThreadPool(1);
- mNetworkScanHelper = new NetworkScanHelper(mTelephonyManager,
+ mNetworkScanHelper = new NetworkScanHelper(null, mTelephonyManager,
mNetworkScanCallback, mNetworkScanExecutor);
mNetworkScan = spy(new NetworkScanMock(SCAN_ID, SUB_ID));
diff --git a/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java
index 6bca9ab892..5eb9513767 100644
--- a/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java
+++ b/tests/unit/src/com/android/settings/network/telephony/PreferredNetworkModePreferenceControllerTest.java
@@ -37,6 +37,7 @@ import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import androidx.lifecycle.Lifecycle;
import androidx.preference.ListPreference;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -62,6 +63,8 @@ public class PreferredNetworkModePreferenceControllerTest {
private CarrierConfigManager mCarrierConfigManager;
@Mock
private ServiceState mServiceState;
+ @Mock
+ private Lifecycle mLifecycle;
private PersistableBundle mPersistableBundle;
private PreferredNetworkModePreferenceController mController;
@@ -87,7 +90,7 @@ public class PreferredNetworkModePreferenceControllerTest {
mPreference = new ListPreference(mContext);
mController = new PreferredNetworkModePreferenceController(mContext, "mobile_data");
- mController.init(SUB_ID);
+ mController.init(mLifecycle, SUB_ID);
mPreference.setKey(mController.getPreferenceKey());
}
diff --git a/tests/unit/src/com/android/settings/panel/PanelFeatureProviderImplTest.java b/tests/unit/src/com/android/settings/panel/PanelFeatureProviderImplTest.java
index a02c054237..952dd51ce5 100644
--- a/tests/unit/src/com/android/settings/panel/PanelFeatureProviderImplTest.java
+++ b/tests/unit/src/com/android/settings/panel/PanelFeatureProviderImplTest.java
@@ -33,6 +33,7 @@ import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceControllerTest.java b/tests/unit/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceControllerTest.java
deleted file mode 100644
index 3d8b24c5f2..0000000000
--- a/tests/unit/src/com/android/settings/wifi/tether/WifiTetherMaximizeCompatibilityPreferenceControllerTest.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settings.wifi.tether;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.content.Context;
-import android.net.wifi.SoftApConfiguration;
-import android.net.wifi.WifiManager;
-import android.os.Looper;
-
-import androidx.preference.PreferenceManager;
-import androidx.preference.PreferenceScreen;
-import androidx.preference.SwitchPreference;
-import androidx.test.core.app.ApplicationProvider;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.settings.testutils.ResourcesUtils;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnit;
-import org.mockito.junit.MockitoRule;
-
-@RunWith(AndroidJUnit4.class)
-public class WifiTetherMaximizeCompatibilityPreferenceControllerTest {
-
- @Rule
- public final MockitoRule mMockitoRule = MockitoJUnit.rule();
- @Mock
- private WifiManager mWifiManager;
- @Mock
- private WifiTetherBasePreferenceController.OnTetherConfigUpdateListener mListener;
-
- private Context mContext;
- private WifiTetherMaximizeCompatibilityPreferenceController mController;
- private SwitchPreference mPreference;
- private SoftApConfiguration mConfig;
-
- @Before
- public void setUp() {
- mContext = spy(ApplicationProvider.getApplicationContext());
- mConfig = new SoftApConfiguration.Builder()
- .setSsid("test_Ssid")
- .setPassphrase(null, SoftApConfiguration.SECURITY_TYPE_OPEN)
- .setBridgedModeOpportunisticShutdownEnabled(true)
- .build();
- doReturn(mWifiManager).when(mContext).getSystemService(Context.WIFI_SERVICE);
- doReturn(true).when(mWifiManager).isBridgedApConcurrencySupported();
- doReturn(mConfig).when(mWifiManager).getSoftApConfiguration();
-
- mController = new WifiTetherMaximizeCompatibilityPreferenceController(mContext, mListener);
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
- final PreferenceManager preferenceManager = new PreferenceManager(mContext);
- final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
- mPreference = new SwitchPreference(mContext);
- mPreference.setKey(WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY);
- screen.addPreference(mPreference);
- mController.displayPreference(screen);
- }
-
- @Test
- public void getPreferenceKey_shouldBeCorrect() {
- assertThat(mController.getPreferenceKey())
- .isEqualTo(WifiTetherMaximizeCompatibilityPreferenceController.PREF_KEY);
- }
-
- @Test
- public void updateDisplay_notSupport5GHzBand_setPreferenceDisabled() {
- doReturn(false).when(mWifiManager).is5GHzBandSupported();
-
- mController.updateDisplay();
-
- assertThat(mPreference.isEnabled()).isEqualTo(false);
- }
-
- @Test
- public void updateDisplay_getNullCountryCode_setPreferenceDisabled() {
- doReturn(null).when(mWifiManager).getCountryCode();
-
- mController.updateDisplay();
-
- assertThat(mPreference.isEnabled()).isEqualTo(false);
- }
-
- @Test
- public void updateDisplay_notSupportedBridgedApConcurrency_setSingleApSummary() {
- doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
-
- mController.updateDisplay();
-
- assertThat(mPreference.getSummary()).isEqualTo(ResourcesUtils.getResourcesString(mContext,
- "wifi_hotspot_maximize_compatibility_single_ap_summary"));
- }
-
- @Test
- public void updateDisplay_supportedBridgedApConcurrency_setDualApSummary() {
- doReturn(true).when(mWifiManager).isBridgedApConcurrencySupported();
-
- mController.updateDisplay();
-
- assertThat(mPreference.getSummary()).isEqualTo(ResourcesUtils.getResourcesString(mContext,
- "wifi_hotspot_maximize_compatibility_dual_ap_summary"));
- }
-
- @Test
- public void updateDisplay_supported5GHzBandAndCountryCodeIsNotNull_setPreferenceEnabled() {
- doReturn(true).when(mWifiManager).is5GHzBandSupported();
- doReturn("US").when(mWifiManager).getCountryCode();
-
- mController.updateDisplay();
-
- assertThat(mPreference.isEnabled()).isEqualTo(true);
- }
-
- @Test
- public void onPreferenceChange_callbackOnTetherConfigUpdated() {
- mController.onPreferenceChange(mPreference, true);
- verify(mListener).onTetherConfigUpdated(any());
- }
-
- @Test
- public void isMaximizeCompatibilityEnabled_concurrencySupportedAndEnabled_returnFalse() {
- // The preconditions are ready in setup().
-
- assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(false);
- }
-
- @Test
- public void isMaximizeCompatibilityEnabled_concurrencySupportedAndDisabled_returnTrue() {
- SoftApConfiguration config = new SoftApConfiguration.Builder()
- .setBridgedModeOpportunisticShutdownEnabled(false)
- .build();
- doReturn(config).when(mWifiManager).getSoftApConfiguration();
-
- assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(true);
- }
-
- @Test
- public void isMaximizeCompatibilityEnabled_noConcurrencyAndGetBand2gOnly_returnFalse() {
- doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
- SoftApConfiguration config = new SoftApConfiguration.Builder()
- .setBand(SoftApConfiguration.BAND_2GHZ)
- .build();
- doReturn(config).when(mWifiManager).getSoftApConfiguration();
-
- assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(true);
- }
-
- @Test
- public void isMaximizeCompatibilityEnabled_noConcurrencyAndGetBand5gOnly_returnTrue() {
- doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
- SoftApConfiguration config = new SoftApConfiguration.Builder()
- .setBand(SoftApConfiguration.BAND_5GHZ)
- .build();
- doReturn(config).when(mWifiManager).getSoftApConfiguration();
-
- assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(false);
- }
-
- @Test
- public void isMaximizeCompatibilityEnabled_noConcurrencyAndGetBand2gAnd5g_returnTrue() {
- doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
- SoftApConfiguration config = new SoftApConfiguration.Builder()
- .setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ)
- .build();
- doReturn(config).when(mWifiManager).getSoftApConfiguration();
-
- assertThat(mController.isMaximizeCompatibilityEnabled()).isEqualTo(false);
- }
-
- @Test
- public void setupMaximizeCompatibility_concurrencySupportedAndDisabled_setEnabled() {
- // The precondition of the concurrency supported is ready in setup().
- mController.onPreferenceChange(mPreference, false);
-
- SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
- mController.setupMaximizeCompatibility(builder);
-
- assertThat(builder.build().isBridgedModeOpportunisticShutdownEnabled()).isEqualTo(true);
- }
-
- @Test
- public void setupMaximizeCompatibility_concurrencySupportedAndEnabled_setDisabled() {
- // The precondition of the concurrency supported is ready in setup().
- mController.onPreferenceChange(mPreference, true);
-
- SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
- mController.setupMaximizeCompatibility(builder);
-
- assertThat(builder.build().isBridgedModeOpportunisticShutdownEnabled()).isEqualTo(false);
- }
-
- @Test
- public void setupMaximizeCompatibility_noConcurrencyAndSetDisabled_setBand2gOnly() {
- doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
- mController.onPreferenceChange(mPreference, false);
-
- SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
- mController.setupMaximizeCompatibility(builder);
-
- assertThat(builder.build().getBand())
- .isEqualTo(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ);
- }
-
- @Test
- public void setupMaximizeCompatibility_noConcurrencyAndSetEnabled_setBand2gAnd5g() {
- doReturn(false).when(mWifiManager).isBridgedApConcurrencySupported();
- mController.onPreferenceChange(mPreference, true);
-
- SoftApConfiguration.Builder builder = new SoftApConfiguration.Builder();
- mController.setupMaximizeCompatibility(builder);
-
- assertThat(builder.build().getBand()).isEqualTo(SoftApConfiguration.BAND_2GHZ);
- }
-}