From 13f75dcf2b5607ea6a038889411eeab950539aa9 Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Tue, 14 Mar 2023 20:01:22 +0000 Subject: [PATCH 01/14] Remove RESTRICTED bucket off code. The RESTRICTED bucket has been enabled for a few releases and we have no intention of disabling it by itself at this point. Bug: 273564840 Test: atest CtsJobSchedulerTestCases:ConnectivityConstraintTest Test: atest CtsJobSchedulerTestCases:JobThrottlingTest Test: atest CtsUsageStatsTestCases:UsageStatsTest Change-Id: I51bfd0b00bb582a839a356e8d926a6d0ca81a683 --- .../android/settings/fuelgauge/InactiveApps.java | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/com/android/settings/fuelgauge/InactiveApps.java b/src/com/android/settings/fuelgauge/InactiveApps.java index 0d87ae73fe6..284e5be6c1f 100644 --- a/src/com/android/settings/fuelgauge/InactiveApps.java +++ b/src/com/android/settings/fuelgauge/InactiveApps.java @@ -32,7 +32,6 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.os.Bundle; -import android.provider.Settings; import android.text.TextUtils; import androidx.preference.ListPreference; @@ -51,9 +50,6 @@ public class InactiveApps extends SettingsPreferenceFragment private static final CharSequence[] FULL_SETTABLE_BUCKETS_NAMES = {"ACTIVE", "WORKING_SET", "FREQUENT", "RARE", "RESTRICTED"}; - private static final CharSequence[] REDUCED_SETTABLE_BUCKETS_NAMES = - Arrays.copyOfRange(FULL_SETTABLE_BUCKETS_NAMES, 0, 4); - private static final CharSequence[] FULL_SETTABLE_BUCKETS_VALUES = { Integer.toString(STANDBY_BUCKET_ACTIVE), Integer.toString(STANDBY_BUCKET_WORKING_SET), @@ -62,9 +58,6 @@ public class InactiveApps extends SettingsPreferenceFragment Integer.toString(STANDBY_BUCKET_RESTRICTED) }; - private static final CharSequence[] REDUCED_SETTABLE_BUCKETS_VALUES = - Arrays.copyOfRange(FULL_SETTABLE_BUCKETS_VALUES, 0, 4); - private UsageStatsManager mUsageStats; @Override @@ -94,13 +87,8 @@ public class InactiveApps extends SettingsPreferenceFragment final Context context = getActivity(); final PackageManager pm = context.getPackageManager(); final String settingsPackage = context.getPackageName(); - final boolean allowRestrictedBucket = Settings.Global.getInt(getContentResolver(), - Settings.Global.ENABLE_RESTRICTED_BUCKET, - Settings.Global.DEFAULT_ENABLE_RESTRICTED_BUCKET) == 1; - final CharSequence[] bucketNames = allowRestrictedBucket - ? FULL_SETTABLE_BUCKETS_NAMES : REDUCED_SETTABLE_BUCKETS_NAMES; - final CharSequence[] bucketValues = allowRestrictedBucket - ? FULL_SETTABLE_BUCKETS_VALUES : REDUCED_SETTABLE_BUCKETS_VALUES; + final CharSequence[] bucketNames = FULL_SETTABLE_BUCKETS_NAMES; + final CharSequence[] bucketValues = FULL_SETTABLE_BUCKETS_VALUES; Intent launcherIntent = new Intent(Intent.ACTION_MAIN); launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER); From 82c23db452a14732c993e4238d13d015b66d7385 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 16 Mar 2023 20:40:36 -0700 Subject: [PATCH 02/14] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: Ie8640533b71ecdb1baf669edd91ed6df54df8a4d --- res/values-fa/arrays.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values-fa/arrays.xml b/res/values-fa/arrays.xml index 26658b417bb..1f0e726ba27 100644 --- a/res/values-fa/arrays.xml +++ b/res/values-fa/arrays.xml @@ -517,7 +517,7 @@ "خاموش" "اشکال‌زدایی" - "درازنویسی" + "مفصل" "فقط خانه" From 71e954c78bebf044f61c922718ab154a234d3994 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 16 Mar 2023 20:45:10 -0700 Subject: [PATCH 03/14] Import translations. DO NOT MERGE ANYWHERE Auto-generated-cl: translation import Change-Id: I79c7f425dac1cd278eface63dc0c3702616bfc88 --- res/values-en-rAU/strings.xml | 2 +- res/values-en-rCA/strings.xml | 6 ++---- res/values-en-rGB/strings.xml | 2 +- res/values-en-rIN/strings.xml | 2 +- res/values-en-rXC/strings.xml | 6 ++---- res/values-fr/strings.xml | 2 +- res/values-hr/strings.xml | 2 +- res/values-km/strings.xml | 2 +- res/values-ky/strings.xml | 4 ++-- res/values-my/strings.xml | 6 +++--- res/values-uk/strings.xml | 2 +- res/values-zh-rTW/strings.xml | 2 +- 12 files changed, 17 insertions(+), 21 deletions(-) diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml index 9cc3d8305aa..22ed8bf2a8f 100644 --- a/res/values-en-rAU/strings.xml +++ b/res/values-en-rAU/strings.xml @@ -2497,7 +2497,7 @@ "Accessibility gesture" "Swipe up with 2 fingers" "Swipe up with three fingers" - "Tap accessibility button" + "Tap Accessibility button" "Use accessibility gesture" "Tap the accessibility button %s at the bottom of your screen.\n\nTo switch between features, touch and hold the accessibility button." "Swipe up from the bottom of the screen with 2 fingers.\n\nTo switch between features, swipe up with 2 fingers and hold." diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml index c908df5668e..d1d8cc32a6e 100644 --- a/res/values-en-rCA/strings.xml +++ b/res/values-en-rCA/strings.xml @@ -5927,10 +5927,8 @@ "Choose a screen saver" "Show additional information" "Display things like the time, weather, or other information on the screen saver" - - - - + "Show home controls" + "Show home controls button from the screen saver" "More settings" "Choose your screen saver" "Choose what you’ll see on your screen when your tablet is docked. Your device may use more energy when a screen saver is used." diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml index 061680020e6..8254f837d3a 100644 --- a/res/values-en-rGB/strings.xml +++ b/res/values-en-rGB/strings.xml @@ -2497,7 +2497,7 @@ "Accessibility gesture" "Swipe up with 2 fingers" "Swipe up with three fingers" - "Tap accessibility button" + "Tap Accessibility button" "Use accessibility gesture" "Tap the accessibility button %s at the bottom of your screen.\n\nTo switch between features, touch and hold the accessibility button." "Swipe up from the bottom of the screen with 2 fingers.\n\nTo switch between features, swipe up with 2 fingers and hold." diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml index 50a05abbab9..e6841e5d051 100644 --- a/res/values-en-rIN/strings.xml +++ b/res/values-en-rIN/strings.xml @@ -2497,7 +2497,7 @@ "Accessibility gesture" "Swipe up with 2 fingers" "Swipe up with three fingers" - "Tap accessibility button" + "Tap Accessibility button" "Use accessibility gesture" "Tap the accessibility button %s at the bottom of your screen.\n\nTo switch between features, touch and hold the accessibility button." "Swipe up from the bottom of the screen with 2 fingers.\n\nTo switch between features, swipe up with 2 fingers and hold." diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml index fa6470ad928..7e130a028ac 100644 --- a/res/values-en-rXC/strings.xml +++ b/res/values-en-rXC/strings.xml @@ -5927,10 +5927,8 @@ "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‎‏‏‏‎‏‏‎‏‏‎‏‎‏‏‏‏‏‎‎‎‎‎‏‎‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎Choose a screen saver‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‎‏‎‏‏‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‏‎Show additional information‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‎‎‎‏‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‎Display things like the time, weather, or other information on the screen saver‎‏‎‎‏‎" - - - - + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‎‎‏‏‏‎‎‎‏‎‎‎‎‎Show home controls‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‏‏‎‎‏‏‎Show home controls button from the screen saver‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‎‏‎‎‏‏‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‏‎‏‎‏‏‏‎‏‏‏‎‏‎‎‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎More settings‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‏‎‏‏‎‎‏‎‏‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‎‎‏‏‏‎‏‎‎‏‎‏‏‏‎‎Choose your screen saver‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‏‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‏‎‎‎‏‎‎‏‎‎‎‎Choose what you’ll see on your screen when your tablet is docked. Your device may use more energy when a screen saver is used.‎‏‎‎‏‎" diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index 2026c7eabce..559e21b2ce3 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -2421,7 +2421,7 @@ "Commandes système" "Applications téléchargées" "Paramètres expérimentaux" - "Fonctionnalités expérimentales" + "Flags de fonctionnalités" "TalkBack" "Le lecteur d\'écran est destiné principalement aux personnes atteintes de cécité ou de troubles de la vue" "Appuyez sur des éléments à l\'écran pour qu\'ils soient lus à voix haute" diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index 6c2e761db7d..6cda0c94612 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -1739,7 +1739,7 @@ "Zaboravi" "Postavi" "Oslobađanje prostora" - "Upravljaj pohranom" + "Upravljajte pohranom" "čisti, pohrana" "Oslobađanje prostora" "Otvorite aplikaciju Files da biste oslobodili prostor i upravljali njime" diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml index 3d932d8831d..6eb2ff21a4a 100644 --- a/res/values-km/strings.xml +++ b/res/values-km/strings.xml @@ -4523,7 +4523,7 @@ "បញ្ចូល" "បើកនៅក្នុង %s" - "បានប្រើអស់%1$s នៅក្នុង %2$s" + "បានប្រើអស់ %1$s នៅក្នុង​%2$s" "ទំហំផ្ទុក​ខាងក្នុង" "ទំហំផ្ទុក​ខាងក្រៅ" "បានប្រើ %1$s ចាប់តាំងពី %2$s" diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml index 7c7cf8a7372..1fb0560f9ac 100644 --- a/res/values-ky/strings.xml +++ b/res/values-ky/strings.xml @@ -999,8 +999,8 @@ "Жөндөөлөрдү эстеп калуу" "Туташып турган Bluetooth аудио түзмөктөрүнүн уруксат берилген эң жогорку саны" "Туташып турган Bluetooth аудио түзмөктөрүнүн эң жогорку санын тандоо" - "Мүчүлүштүктөрдү оңдоо үчүн NFC топтомун жайгаштыруу" - "NFC топтомун жайгаштыруу деңгээлин жогорулатуу" + "NFC топтомунун мүчүлүштүктөрүн оңдоо таржымалы" + "NFC топтомунун толук таржымалы жүргүзүлөт" "Тышкы экранга чыгаруу" "күзгү" "Зымсыз мониторду иштетүү" diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml index c1b01739ddd..c5f7f374332 100644 --- a/res/values-my/strings.xml +++ b/res/values-my/strings.xml @@ -573,9 +573,9 @@ "ဖွင့်ပိတ်ခလုတ်ကို မနှိပ်ဘဲ ထိရုံထိပါ" "သင့်လက်ဗွေ စနစ်ထည့်သွင်းနည်း" "၎င်းသည် သင့်ဖုန်း၏ ကျောဘက်တွင်ရှိပါသည်။ လက်ညှိုးကို အသုံးပြုပါ။" - "လက်ဗွေ အာရုံခံကိရိယာသည် ဖွင့်ပိတ်ခလုတ်ပေါ်တွင် ရှိသည်။ တက်ဘလက် ဘေးဘက်ရှိ မြင့်တက်နေသည့်အသံထိန်းခလုတ်နှင့် ကပ်လျက်ရှိသော ခလုတ်ပြားဖြစ်သည်။" - "လက်ဗွေ အာရုံခံကိရိယာသည် ဖွင့်ပိတ်ခလုတ်ပေါ်တွင် ရှိသည်။ စက်ဘေးဘက်ရှိ မြင့်တက်နေသည့်အသံထိန်းခလုတ်နှင့် ကပ်လျက်ရှိသော ခလုတ်ပြားဖြစ်သည်။" - "လက်ဗွေ အာရုံခံကိရိယာသည် ဖွင့်ပိတ်ခလုတ်ပေါ်တွင် ရှိသည်။ ဖုန်းဘေးဘက်ရှိ မြင့်တက်နေသည့်အသံထိန်းခလုတ်နှင့် ကပ်လျက်ရှိသော ခလုတ်ပြားဖြစ်သည်။" + "လက်ဗွေ အာရုံခံကိရိယာသည် ဖွင့်ပိတ်ခလုတ်ပေါ်တွင် ရှိသည်။ တက်ဘလက်၏ဘေးဘက်ရှိ အသံထိန်းခလုတ်ဖုသီးနှင့် ကပ်လျက်မှ ခလုတ်ပြားဖြစ်သည်။" + "လက်ဗွေ အာရုံခံကိရိယာသည် ဖွင့်ပိတ်ခလုတ်ပေါ်တွင် ရှိသည်။ စက်၏ဘေးဘက်ရှိ အသံထိန်းခလုတ်ဖုသီးနှင့် ကပ်လျက်မှ ခလုတ်ပြားဖြစ်သည်။" + "လက်ဗွေ အာရုံခံကိရိယာသည် ဖွင့်ပိတ်ခလုတ်ပေါ်တွင် ရှိသည်။ ဖုန်း၏ဘေးဘက်ရှိ အသံထိန်းခလုတ်ဖုသီးနှင့် ကပ်လျက်မှ ခလုတ်ပြားဖြစ်သည်။" "လက်ဗွေ အာရုံခံကိရိယာသည် သင့်စခရင်ပေါ်တွင်ရှိသည်။ နောက်စခရင်တွင် သင့်လက်ဗွေကို ရိုက်ကူးပါ။" "စတင်ရန်" "အာရုံခံကိရိယာကို ရှာရန် သင့်လက်ချောင်းကို စခရင်ပေါ်တွင် ရွှေ့ပါ။ လက်ဗွေ အာရုံခံကိရိယာကို တို့ထိ၍ ဖိထားပါ။" diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml index 750c7e319b3..9c77aa4f739 100644 --- a/res/values-uk/strings.xml +++ b/res/values-uk/strings.xml @@ -240,7 +240,7 @@ "Текст відображатиметься іншою мовою" "Не можна видалити всі мови" - "Залишіть принаймні одну вибрану мову" + "Залиште принаймні одну вибрану мову" "Може не бути в деяких додатках" "Перемістити вгору" "Перемістити вниз" diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml index 32f833742b4..2c668ecd187 100644 --- a/res/values-zh-rTW/strings.xml +++ b/res/values-zh-rTW/strings.xml @@ -999,7 +999,7 @@ "記住設定" "已連線藍牙音訊裝置的數量上限" "選取已連線藍牙音訊裝置的數量上限" - "NFC 堆疊偵錯記錄" + "NFC 堆疊偵錯記錄檔" "提高 NFC 堆疊記錄等級" "投放" "鏡像" From fb4488ea83c4d498ce9eb4bcd505ba92c2a125ee Mon Sep 17 00:00:00 2001 From: Becca Hughes Date: Thu, 23 Feb 2023 19:52:53 +0000 Subject: [PATCH 04/14] Add subtitle to settings (settings) Allows a credential provider to show a subtitle/summary underneath the title in the list of providers. Test: ondevice & atest Bug: 253157366 Change-Id: I481da16985027a49ee464623b6db166d941cab55 (cherry picked from commit on googleplex-android-review.googlesource.com host: 6474e013727806b2d3b6c619818c21eb4f2cf310) Merged-In: I481da16985027a49ee464623b6db166d941cab55 --- ...CredentialManagerPreferenceController.java | 12 +++++-- ...entialManagerPreferenceControllerTest.java | 32 +++++++++++++++---- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java index 8621e6f5f95..e16d0d8c576 100644 --- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java +++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java @@ -207,7 +207,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl } // Build the pref and add it to the output & group. - SwitchPreference pref = addProviderPreference(context, title, icon, packageName); + SwitchPreference pref = addProviderPreference(context, title, icon, packageName, firstInfo.getSettingsSubtitle()); output.put(packageName, pref); group.addPreference(pref); } @@ -223,7 +223,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl context, label == null ? "" : label, service.getServiceIcon(mContext), - service.getServiceInfo().packageName); + service.getServiceInfo().packageName, + service.getSettingsSubtitle()); } /** @@ -281,7 +282,8 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl @NonNull Context prefContext, @NonNull CharSequence title, @Nullable Drawable icon, - @NonNull String packageName) { + @NonNull String packageName, + @Nullable CharSequence subtitle) { final SwitchPreference pref = new SwitchPreference(prefContext); pref.setTitle(title); pref.setChecked(mEnabledPackageNames.contains(packageName)); @@ -290,6 +292,10 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl pref.setIcon(Utils.getSafeIcon(icon)); } + if (subtitle != null) { + pref.setSummary(subtitle); + } + pref.setOnPreferenceClickListener( p -> { boolean isChecked = pref.isChecked(); diff --git a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java index 39fd6577324..9cfa7ed20c9 100644 --- a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java @@ -75,7 +75,7 @@ public class CredentialManagerPreferenceControllerTest { mScreen.addPreference(mCredentialsPreferenceCategory); } - @Test + /*@Test // Tests that getAvailabilityStatus() does not throw an exception if it's called before the // Controller is initialized (this can happen during indexing). public void getAvailabilityStatus_withoutInit_returnsUnavailable() { @@ -122,11 +122,11 @@ public class CredentialManagerPreferenceControllerTest { @Test public void buildSwitchPreference() { CredentialProviderInfo providerInfo1 = - createCredentialProviderInfoWithIsEnabled( - "com.android.provider1", "ClassA", "Service Title", false); + createCredentialProviderInfoWithSubtitle( + "com.android.provider1", "ClassA", "Service Title", null); CredentialProviderInfo providerInfo2 = - createCredentialProviderInfoWithIsEnabled( - "com.android.provider2", "ClassA", "Service Title", false); + createCredentialProviderInfoWithSubtitle( + "com.android.provider2", "ClassA", "Service Title", "Summary Text"); CredentialManagerPreferenceController controller = createControllerWithServices(Lists.newArrayList(providerInfo1, providerInfo2)); assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); @@ -147,11 +147,13 @@ public class CredentialManagerPreferenceControllerTest { SwitchPreference pref = controller.createPreference(mContext, providerInfo1); assertThat(pref.getTitle().toString()).isEqualTo("Service Title"); assertThat(pref.isChecked()).isTrue(); + assertThat(pref.getSummary()).isNull(); // Create the pref (not checked). SwitchPreference pref2 = controller.createPreference(mContext, providerInfo2); assertThat(pref2.getTitle().toString()).isEqualTo("Service Title"); assertThat(pref2.isChecked()).isFalse(); + assertThat(pref2.getSummary().toString()).isEqualTo("Summary Text"); } @Test @@ -250,7 +252,7 @@ public class CredentialManagerPreferenceControllerTest { assertThat(enabledServices.size()).isEqualTo(1); assertThat(enabledServices.contains("com.android.provider1/ClassA")).isFalse(); assertThat(enabledServices.contains("com.android.provider2/ClassA")).isTrue(); - } + }*/ @Test public void displayPreference_withServices_preferencesAdded_sameAppShouldBeMerged() { @@ -297,6 +299,7 @@ public class CredentialManagerPreferenceControllerTest { Map prefs = controller.buildPreferenceList(mContext, mCredentialsPreferenceCategory); + assertThat(prefs.keySet()).containsExactly(TEST_PACKAGE_NAME_A, TEST_PACKAGE_NAME_B, TEST_PACKAGE_NAME_C); assertThat(prefs.size()).isEqualTo(3); assertThat(prefs.containsKey(TEST_PACKAGE_NAME_A)).isTrue(); assertThat(prefs.get(TEST_PACKAGE_NAME_A).getTitle()).isEqualTo(TEST_TITLE_APP_A); @@ -335,6 +338,23 @@ public class CredentialManagerPreferenceControllerTest { .build(); } + private CredentialProviderInfo createCredentialProviderInfoWithSubtitle( + String packageName, String className, CharSequence label, CharSequence subtitle) { + ServiceInfo si = new ServiceInfo(); + si.packageName = packageName; + si.name = className; + si.nonLocalizedLabel = "test"; + + si.applicationInfo = new ApplicationInfo(); + si.applicationInfo.packageName = packageName; + si.applicationInfo.nonLocalizedLabel = "test"; + + return new CredentialProviderInfo.Builder(si) + .setOverrideLabel(label) + .setSettingsSubtitle(subtitle) + .build(); + } + private CredentialProviderInfo createCredentialProviderInfoWithAppLabel( String packageName, String className, CharSequence serviceLabel, String appLabel) { return createCredentialProviderInfoBuilder(packageName, className, serviceLabel, appLabel) From 76bb350c73db974d049db6be8575fb4271fd1330 Mon Sep 17 00:00:00 2001 From: Zoey Chen Date: Fri, 17 Mar 2023 18:14:49 +0000 Subject: [PATCH 05/14] [Settings] Do not set text if the fragment is not attached Bug: 273415166 Test: loacl test Change-Id: I5298727359191d8ce9c4526279faa4e8a3c1df43 --- .../deviceinfo/simstatus/SimStatusDialogFragment.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java index 4105db1037e..e82d54163fb 100644 --- a/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java +++ b/src/com/android/settings/deviceinfo/simstatus/SimStatusDialogFragment.java @@ -20,6 +20,7 @@ import android.app.Dialog; import android.app.settings.SettingsEnums; import android.os.Bundle; import android.text.TextUtils; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.WindowManager; @@ -106,6 +107,10 @@ public class SimStatusDialogFragment extends InstrumentedDialogFragment { .sorted().toArray(); public void setText(int viewId, CharSequence text) { + if (!isAdded()) { + Log.d(TAG, "Fragment not attached yet."); + return; + } setText(viewId, text, true); } From 85dd572f18fd9d49f94265aa5d7a0436abbb04d2 Mon Sep 17 00:00:00 2001 From: changbetty Date: Mon, 19 Sep 2022 08:34:53 +0000 Subject: [PATCH 06/14] [LE Audio] To remove the broadcast source item that created by receive state - When the user clicks another broadcast source and wants to join, we will remove the previous item that created by getAllSource(). And trigger the search again. Bug: 242267719 Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothBroadcastSourcePreferenceTest Test: make RunSettingsRoboTests ROBOTEST_FILTER=BluetoothFindBroadcastsFragmentTest Change-Id: I416f0a39e31276876e63360664555f99dd7297c9 Merged-In: I416f0a39e31276876e63360664555f99dd7297c9 --- .../BluetoothBroadcastSourcePreference.java | 10 ++ .../BluetoothFindBroadcastsFragment.java | 23 ++- ...luetoothBroadcastSourcePreferenceTest.java | 71 +++++++++ .../BluetoothFindBroadcastsFragmentTest.java | 148 ++++++++++++++++++ 4 files changed, 247 insertions(+), 5 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/bluetooth/BluetoothBroadcastSourcePreferenceTest.java create mode 100644 tests/robotests/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragmentTest.java diff --git a/src/com/android/settings/bluetooth/BluetoothBroadcastSourcePreference.java b/src/com/android/settings/bluetooth/BluetoothBroadcastSourcePreference.java index 733a4a96e49..9904e8b81f9 100644 --- a/src/com/android/settings/bluetooth/BluetoothBroadcastSourcePreference.java +++ b/src/com/android/settings/bluetooth/BluetoothBroadcastSourcePreference.java @@ -170,6 +170,16 @@ class BluetoothBroadcastSourcePreference extends Preference { return mIsEncrypted; } + /** + * Whether the broadcast source is connected at the beginging. We will get the + * BluetoothLeBroadcastReceiveState from the broadcast source. + * See {@link BluetoothFindBroadcastsFragment#addConnectedSourcePreference} + * @return If true, the broadcast source is already connected by the broadcast sink. + */ + public boolean isCreatedByReceiveState() { + return mBluetoothLeBroadcastReceiveState != null; + } + /** * Clear the BluetoothLeBroadcastReceiveState and reset the state when the user clicks the * "leave broadcast" button. diff --git a/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java b/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java index 13388b3ecd3..e08a2446e18 100644 --- a/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java +++ b/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java @@ -37,7 +37,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; -import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import com.android.settings.R; @@ -75,9 +74,11 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment CachedBluetoothDevice mCachedDevice; @VisibleForTesting PreferenceCategory mBroadcastSourceListCategory; + @VisibleForTesting + BluetoothBroadcastSourcePreference mSelectedPreference; BluetoothFindBroadcastsHeaderController mBluetoothFindBroadcastsHeaderController; + private LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant; - private BluetoothBroadcastSourcePreference mSelectedPreference; private Executor mExecutor; private int mSourceId; @@ -369,19 +370,31 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment return pref; } - private void addSource(BluetoothBroadcastSourcePreference pref) { + @VisibleForTesting + void addSource(BluetoothBroadcastSourcePreference pref) { if (mLeBroadcastAssistant == null || mCachedDevice == null) { Log.w(TAG, "addSource: LeBroadcastAssistant or CachedDevice is null!"); return; } if (mSelectedPreference != null) { - // The previous preference status set false after user selects the new Preference. - getActivity().runOnUiThread( + if (mSelectedPreference.isCreatedByReceiveState()) { + Log.d(TAG, "addSource: Remove preference that created by getAllSources()"); + getActivity().runOnUiThread(() -> + mBroadcastSourceListCategory.removePreference(mSelectedPreference)); + if (mLeBroadcastAssistant != null && !mLeBroadcastAssistant.isSearchInProgress()) { + Log.d(TAG, "addSource: Start Searching For Broadcast Sources"); + mLeBroadcastAssistant.startSearchingForSources(getScanFilter()); + } + } else { + Log.d(TAG, "addSource: Update preference that created by onSourceFound()"); + // The previous preference status set false after user selects the new Preference. + getActivity().runOnUiThread( () -> { mSelectedPreference.updateMetadataAndRefreshUi( mSelectedPreference.getBluetoothLeBroadcastMetadata(), false); mSelectedPreference.setOrder(1); }); + } } mSelectedPreference = pref; mLeBroadcastAssistant.addSource(mCachedDevice.getDevice(), diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothBroadcastSourcePreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothBroadcastSourcePreferenceTest.java new file mode 100644 index 00000000000..85d12b928b1 --- /dev/null +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothBroadcastSourcePreferenceTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.bluetooth.BluetoothLeBroadcastReceiveState; +import android.content.Context; + +import androidx.test.core.app.ApplicationProvider; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class BluetoothBroadcastSourcePreferenceTest { + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Spy + Context mContext = ApplicationProvider.getApplicationContext(); + @Mock + BluetoothLeBroadcastReceiveState mBroadcastReceiveState; + @Mock + BluetoothLeBroadcastMetadata mBroadcastMetadata; + + BluetoothBroadcastSourcePreference mPreference; + + + @Before + public void setUp() { + mPreference = new BluetoothBroadcastSourcePreference(mContext); + } + + @Test + public void isCreatedByReceiveState_updateUiFromReceviceState_returnsTrue() { + mPreference.updateReceiveStateAndRefreshUi(mBroadcastReceiveState); + + assertThat(mPreference.isCreatedByReceiveState()).isTrue(); + } + + @Test + public void isCreatedByReceiveState_updateUiFromMetadata_returnsFalse() { + mPreference.updateMetadataAndRefreshUi(mBroadcastMetadata, true); + + assertThat(mPreference.isCreatedByReceiveState()).isFalse(); + } + +} diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragmentTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragmentTest.java new file mode 100644 index 00000000000..9551c9a9460 --- /dev/null +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragmentTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.bluetooth; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothLeBroadcastMetadata; +import android.content.Context; +import android.os.Bundle; + +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; +import androidx.preference.PreferenceCategory; + +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant; +import com.android.settingslib.bluetooth.LocalBluetoothManager; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class BluetoothFindBroadcastsFragmentTest { + + private static final String TEST_ADDRESS = "55:66:77:88:99:AA"; + + private BluetoothFindBroadcastsFragment mFragment; + private FragmentActivity mActivity; + private Context mContext; + private FragmentTransaction mFragmentTransaction; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private CachedBluetoothDevice mCachedDevice; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private LocalBluetoothManager mLocalManager; + @Mock + private PreferenceCategory mPreferenceCategroy; + @Mock + private LocalBluetoothLeBroadcastAssistant mBroadcastAssistant; + @Mock + private BluetoothLeBroadcastMetadata mBroadcastMetadata; + @Mock + private BluetoothBroadcastSourcePreference mBroadcastSourcePreference; + @Mock + private BluetoothBroadcastSourcePreference mBroadcastSourcePreferenceUserClick; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + FakeFeatureFactory.setupForTest(); + + mFragment = spy(new BluetoothFindBroadcastsFragment()); + doReturn(mLocalManager).when(mFragment).getLocalBluetoothManager(any()); + doReturn(mCachedDevice).when(mFragment).getCachedDevice(any()); + doReturn(mBroadcastAssistant).when(mFragment).getLeBroadcastAssistant(); + doReturn(mPreferenceCategroy).when(mFragment).findPreference(any()); + mActivity = Robolectric.setupActivity(FragmentActivity.class); + when(mFragment.getActivity()).thenReturn(mActivity); + + FragmentManager fragmentManager = mock(FragmentManager.class); + when(mFragment.getFragmentManager()).thenReturn(fragmentManager); + mFragmentTransaction = mock(FragmentTransaction.class); + when(fragmentManager.beginTransaction()).thenReturn(mFragmentTransaction); + + when(mCachedDevice.getAddress()).thenReturn(TEST_ADDRESS); + when(mCachedDevice.getIdentityAddress()).thenReturn(TEST_ADDRESS); + Bundle args = new Bundle(); + args.putString(BluetoothFindBroadcastsFragment.KEY_DEVICE_ADDRESS, TEST_ADDRESS); + mFragment.setArguments(args); + mFragment.onAttach(mContext); + } + + @Test + public void verifyOnAttachResult() { + assertThat(mFragment.mDeviceAddress).isEqualTo(TEST_ADDRESS); + assertThat(mFragment.mManager).isEqualTo(mLocalManager); + assertThat(mFragment.mCachedDevice).isEqualTo(mCachedDevice); + } + + @Test + public void addSource_selectedPrefIsNull_returnsNewPref() { + mFragment.mSelectedPreference = null; + + mFragment.addSource(mBroadcastSourcePreference); + + assertThat(mFragment.mSelectedPreference).isEqualTo(mBroadcastSourcePreference); + } + + @Test + public void addSource_sourcePrefIsCreatedByReceiveState_removesOldPref() { + mFragment.mSelectedPreference = mBroadcastSourcePreference; + mFragment.mBroadcastSourceListCategory = mPreferenceCategroy; + doReturn(true).when(mFragment.mSelectedPreference).isCreatedByReceiveState(); + + mFragment.addSource(mBroadcastSourcePreferenceUserClick); + + verify(mFragment.mBroadcastSourceListCategory).removePreference(mBroadcastSourcePreference); + assertThat(mFragment.mSelectedPreference).isEqualTo(mBroadcastSourcePreferenceUserClick); + } + + @Test + public void addSource_sourcePrefIsCreatedByMetadata_updatesOldPref() { + when(mBroadcastSourcePreference.isCreatedByReceiveState()).thenReturn(false); + when(mBroadcastSourcePreference.getBluetoothLeBroadcastMetadata()) + .thenReturn(mBroadcastMetadata); + mFragment.mSelectedPreference = mBroadcastSourcePreference; + mFragment.mBroadcastSourceListCategory = mPreferenceCategroy; + + mFragment.addSource(mBroadcastSourcePreferenceUserClick); + + verify(mBroadcastSourcePreference).updateMetadataAndRefreshUi( + any(BluetoothLeBroadcastMetadata.class), anyBoolean()); + assertThat(mFragment.mSelectedPreference).isEqualTo(mBroadcastSourcePreferenceUserClick); + } + +} From 88717f2c3fc6cda7d235ad637893a0ec4ce9cc31 Mon Sep 17 00:00:00 2001 From: SongFerngWang Date: Mon, 6 Mar 2023 17:24:51 +0800 Subject: [PATCH 07/14] Avoid ANR when UI query network selection state Moving the quert network selection state to back ground and listening the service state to detect the betwork selection changed. Bug: 270652395 Test: atest AutoSelectPreferenceControllerTest Merged-In: I81a597f28cf7ce25ff4eff5100bdb4d29c897a14 Merged-In: Idfc7a07106d552c35a94414bb14eac0fbdc3974f Change-Id: Ifb548de301021f992ef13c3d299de1642f379fbf --- .../telephony/MobileNetworkSettings.java | 2 +- .../gsm/AutoSelectPreferenceController.java | 95 ++++++++++++++++--- .../AutoSelectPreferenceControllerTest.java | 53 ++++++++++- 3 files changed, 133 insertions(+), 17 deletions(-) diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index 05e58e96ed7..98add25fdaa 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -211,7 +211,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings { use(OpenNetworkSelectPagePreferenceController.class).init(mSubId); final AutoSelectPreferenceController autoSelectPreferenceController = use(AutoSelectPreferenceController.class) - .init(mSubId) + .init(getLifecycle(), mSubId) .addListener(openNetworkSelectPagePreferenceController); use(NetworkPreferenceCategoryController.class).init(mSubId) .setChildren(Arrays.asList(autoSelectPreferenceController)); diff --git a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java index a19702fcb06..d6da17d00b9 100644 --- a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java +++ b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java @@ -31,9 +31,12 @@ import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; 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.Preference; @@ -60,6 +63,9 @@ import java.util.concurrent.atomic.AtomicLong; public class AutoSelectPreferenceController extends TelephonyTogglePreferenceController implements LifecycleObserver{ private static final long MINIMUM_DIALOG_TIME_MILLIS = TimeUnit.SECONDS.toMillis(1); + private static final String LOG_TAG = "AutoSelectPreferenceController"; + private static final String INTERNAL_LOG_TAG_INIT = "Init"; + private static final String INTERNAL_LOG_TAG_AFTERSET = "AfterSet"; private final Handler mUiHandler; private PreferenceScreen mPreferenceScreen; @@ -74,6 +80,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon private AtomicBoolean mUpdatingConfig; private int mCacheOfModeStatus; private AtomicLong mRecursiveUpdate; + TelephonyCallbackListener mTelephonyCallbackListener; public AutoSelectPreferenceController(Context context, String key) { super(context, key); @@ -88,6 +95,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon new HandlerExecutor(mUiHandler)); mAllowedNetworkTypesListener.setAllowedNetworkTypesListener( () -> updatePreference()); + mTelephonyCallbackListener = new TelephonyCallbackListener(); } private void updatePreference() { @@ -104,11 +112,14 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon @OnLifecycleEvent(ON_START) public void onStart() { mAllowedNetworkTypesListener.register(mContext, mSubId); + mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(mUiHandler), + mTelephonyCallbackListener); } @OnLifecycleEvent(ON_STOP) public void onStop() { mAllowedNetworkTypesListener.unregister(mContext, mSubId); + mTelephonyManager.unregisterTelephonyCallback(mTelephonyCallbackListener); } @Override @@ -127,12 +138,6 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon @Override public boolean isChecked() { - if (!mUpdatingConfig.get()) { - mCacheOfModeStatus = mTelephonyManager.getNetworkSelectionMode(); - for (OnNetworkSelectModeListener lsn : mListeners) { - lsn.onNetworkSelectModeUpdated(mCacheOfModeStatus); - } - } return mCacheOfModeStatus == TelephonyManager.NETWORK_SELECTION_MODE_AUTO; } @@ -195,12 +200,23 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon //Update UI in UI thread final long durationMillis = SystemClock.elapsedRealtime() - startMillis; + mUiHandler.postDelayed(() -> { - mRecursiveUpdate.getAndIncrement(); - mSwitchPreference.setEnabled(true); - mSwitchPreference.setChecked(isChecked()); - mRecursiveUpdate.decrementAndGet(); - dismissProgressBar(); + ThreadUtils.postOnBackgroundThread(() -> { + queryNetworkSelectionMode(INTERNAL_LOG_TAG_AFTERSET); + + //Update UI in UI thread + mUiHandler.post(() -> { + mRecursiveUpdate.getAndIncrement(); + if (mSwitchPreference != null) { + mSwitchPreference.setEnabled(true); + mSwitchPreference.setChecked(isChecked()); + } + mRecursiveUpdate.decrementAndGet(); + updateListenerValue(); + dismissProgressBar(); + }); + }); }, Math.max(MINIMUM_DIALOG_TIME_MILLIS - durationMillis, 0)); }); } @@ -208,7 +224,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon /** * Initialization based on given subscription id. **/ - public AutoSelectPreferenceController init(int subId) { + public AutoSelectPreferenceController init(Lifecycle lifecycle, int subId) { mSubId = subId; mTelephonyManager = mContext.getSystemService(TelephonyManager.class) .createForSubscriptionId(mSubId); @@ -219,6 +235,19 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon CarrierConfigManager.KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL) : false; + ThreadUtils.postOnBackgroundThread(() -> { + queryNetworkSelectionMode(INTERNAL_LOG_TAG_INIT); + + //Update UI in UI thread + mUiHandler.post(() -> { + if (mSwitchPreference != null) { + mRecursiveUpdate.getAndIncrement(); + mSwitchPreference.setChecked(isChecked()); + mRecursiveUpdate.decrementAndGet(); + updateListenerValue(); + } + }); + }); return this; } @@ -228,6 +257,39 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon return this; } + private void queryNetworkSelectionMode(String tag) { + mCacheOfModeStatus = mTelephonyManager.getNetworkSelectionMode(); + Log.d(LOG_TAG, tag + ": query command done. mCacheOfModeStatus: " + mCacheOfModeStatus); + } + + @VisibleForTesting + void updateUiAutoSelectValue(ServiceState status) { + if (status == null) { + return; + } + if (!mUpdatingConfig.get()) { + int networkSelectionMode = status.getIsManualSelection() + ? TelephonyManager.NETWORK_SELECTION_MODE_MANUAL + : TelephonyManager.NETWORK_SELECTION_MODE_AUTO; + if (mCacheOfModeStatus == networkSelectionMode) { + return; + } + mCacheOfModeStatus = networkSelectionMode; + Log.d(LOG_TAG, "updateUiAutoSelectValue: mCacheOfModeStatus: " + mCacheOfModeStatus); + + mRecursiveUpdate.getAndIncrement(); + updateState(mSwitchPreference); + mRecursiveUpdate.decrementAndGet(); + updateListenerValue(); + } + } + + private void updateListenerValue() { + for (OnNetworkSelectModeListener lsn : mListeners) { + lsn.onNetworkSelectModeUpdated(mCacheOfModeStatus); + } + } + private void showAutoSelectProgressBar() { if (mProgressDialog == null) { mProgressDialog = new ProgressDialog(mContext); @@ -258,4 +320,13 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon public interface OnNetworkSelectModeListener { void onNetworkSelectModeUpdated(int mode); } + + private class TelephonyCallbackListener extends TelephonyCallback + implements TelephonyCallback.ServiceStateListener { + + @Override + public void onServiceStateChanged(ServiceState serviceState) { + updateUiAutoSelectValue(serviceState); + } + } } diff --git a/tests/unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.java index 292b4a9ae5c..39f2050b7f7 100644 --- a/tests/unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceControllerTest.java @@ -28,9 +28,11 @@ import android.app.ProgressDialog; import android.content.Context; import android.os.PersistableBundle; import android.telephony.CarrierConfigManager; +import android.telephony.ServiceState; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import androidx.lifecycle.Lifecycle; import androidx.preference.SwitchPreference; import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -61,6 +63,10 @@ public class AutoSelectPreferenceControllerTest { private CarrierConfigCache mCarrierConfigCache; @Mock private ProgressDialog mProgressDialog; + @Mock + private ServiceState mTestServiceState; + @Mock + private Lifecycle mLifecycle; private PersistableBundle mCarrierConfig; private AutoSelectPreferenceController mController; @@ -88,7 +94,16 @@ public class AutoSelectPreferenceControllerTest { mController = new AutoSelectPreferenceController(mContext, "auto_select"); mController.mProgressDialog = mProgressDialog; mController.mSwitchPreference = mSwitchPreference; - mController.init(SUB_ID); + mController.init(mLifecycle, SUB_ID); + sleepAfterInit(); + } + + private void sleepAfterInit() { + try { + Thread.sleep(2000); + } catch (Exception e) { + fail("Sleep timeout " + e); + } } @Test @@ -111,7 +126,8 @@ public class AutoSelectPreferenceControllerTest { @Test public void updateState_isRoaming_enabled() { - when(mTelephonyManager.getServiceState().getRoaming()).thenReturn(true); + when(mTelephonyManager.getServiceState()).thenReturn(mTestServiceState); + when(mTestServiceState.getRoaming()).thenReturn(true); mController.updateState(mSwitchPreference); @@ -120,7 +136,8 @@ public class AutoSelectPreferenceControllerTest { @Test public void updateState_notRoamingWithAutoSelectOn_disabled() { - when(mTelephonyManager.getServiceState().getRoaming()).thenReturn(false); + when(mTelephonyManager.getServiceState()).thenReturn(mTestServiceState); + when(mTestServiceState.getRoaming()).thenReturn(false); doReturn(OPERATOR_NAME).when(mTelephonyManager).getSimOperatorName(); mController.updateState(mSwitchPreference); @@ -136,6 +153,34 @@ public class AutoSelectPreferenceControllerTest { when(mCarrierConfigCache.getConfigForSubId(SUB_ID)).thenReturn(null); // Should not crash - mController.init(SUB_ID); + mController.init(mLifecycle, SUB_ID); + } + + @Test + public void updateUiAutoSelectValue_serviceStateGetIsManualSelection_isCheckedFalse() { + when(mTelephonyManager.getNetworkSelectionMode()).thenReturn( + TelephonyManager.NETWORK_SELECTION_MODE_AUTO); + when(mTestServiceState.getIsManualSelection()).thenReturn(true); + mController.init(mLifecycle, SUB_ID); + sleepAfterInit(); + + mController.updateUiAutoSelectValue(mTestServiceState); + + assertThat(mController.isChecked()).isFalse(); + assertThat(mSwitchPreference.isChecked()).isFalse(); + } + + @Test + public void updateUiAutoSelectValue_serviceStateGetIsAutoSelection_isCheckedTrue() { + when(mTelephonyManager.getNetworkSelectionMode()).thenReturn( + TelephonyManager.NETWORK_SELECTION_MODE_MANUAL); + when(mTestServiceState.getIsManualSelection()).thenReturn(false); + mController.init(mLifecycle, SUB_ID); + sleepAfterInit(); + + mController.updateUiAutoSelectValue(mTestServiceState); + + assertThat(mController.isChecked()).isTrue(); + assertThat(mSwitchPreference.isChecked()).isTrue(); } } From c678caba4ae9a06f5e884032a8172d110b68eada Mon Sep 17 00:00:00 2001 From: SongFerngWang Date: Mon, 20 Mar 2023 14:48:16 +0800 Subject: [PATCH 08/14] Modify the log at AutoSelectPreferenceController Bug: 270652395 Test: build pass Change-Id: I3b9611fd3704d0965ace12f2bb13c28ace60eadf --- .../network/telephony/gsm/AutoSelectPreferenceController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java index c0b903df3c4..e3e83dcb337 100644 --- a/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java +++ b/src/com/android/settings/network/telephony/gsm/AutoSelectPreferenceController.java @@ -267,7 +267,7 @@ public class AutoSelectPreferenceController extends TelephonyTogglePreferenceCon private void queryNetworkSelectionMode(String tag) { mCacheOfModeStatus = mTelephonyManager.getNetworkSelectionMode(); - Log.d(LOG_TAG, tag + ": query commend done. mCacheOfModeStatus: " + mCacheOfModeStatus); + Log.d(LOG_TAG, tag + ": query command done. mCacheOfModeStatus: " + mCacheOfModeStatus); } @VisibleForTesting From 7cf90fbe363d596ccc954088d27d0605ce9118a4 Mon Sep 17 00:00:00 2001 From: changbetty Date: Wed, 8 Mar 2023 06:14:23 +0000 Subject: [PATCH 09/14] [LE Audio] Set activity for result after scanning the QR code Bug: 263554347 Bug: 265281156 Bug: 248409874 Test: manual test Change-Id: Ia252f29ad9dfdc09266e91cc9ecaa32ed8c749c2 Merged-In: Ia252f29ad9dfdc09266e91cc9ecaa32ed8c749c2 --- res/values/strings.xml | 3 +- .../BluetoothFindBroadcastsFragment.java | 39 ++++++++++++ ...uetoothFindBroadcastsHeaderController.java | 3 +- .../bluetooth/QrCodeScanModeController.java | 63 ------------------- .../bluetooth/QrCodeScanModeFragment.java | 14 +++-- 5 files changed, 51 insertions(+), 71 deletions(-) delete mode 100644 src/com/android/settings/bluetooth/QrCodeScanModeController.java diff --git a/res/values/strings.xml b/res/values/strings.xml index cdda50ee4b0..f942ba99785 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -14485,7 +14485,8 @@ Can\u2019t connect. Try again. Wrong password - + + Can\u2019t join the broadcast To start listening, center the QR code below diff --git a/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java b/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java index e08a2446e18..b84654d851f 100644 --- a/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java +++ b/src/com/android/settings/bluetooth/BluetoothFindBroadcastsFragment.java @@ -19,6 +19,7 @@ package com.android.settings.bluetooth; import static android.bluetooth.BluetoothDevice.BOND_NONE; import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH; +import android.app.Activity; import android.app.AlertDialog; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothDevice; @@ -27,6 +28,7 @@ import android.bluetooth.BluetoothLeBroadcastMetadata; import android.bluetooth.BluetoothLeBroadcastReceiveState; import android.bluetooth.le.ScanFilter; import android.content.Context; +import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; @@ -34,6 +36,7 @@ import android.view.View; import android.view.WindowManager; import android.widget.EditText; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; @@ -43,6 +46,7 @@ import com.android.settings.R; import com.android.settings.dashboard.RestrictedDashboardFragment; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant; +import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastMetadata; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import com.android.settingslib.core.AbstractPreferenceController; @@ -65,6 +69,7 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment public static final String KEY_DEVICE_ADDRESS = "device_address"; public static final String PREF_KEY_BROADCAST_SOURCE_LIST = "broadcast_source_list"; + public static final int REQUEST_SCAN_BT_BROADCAST_QR_CODE = 0; @VisibleForTesting String mDeviceAddress; @@ -79,6 +84,7 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment BluetoothFindBroadcastsHeaderController mBluetoothFindBroadcastsHeaderController; private LocalBluetoothLeBroadcastAssistant mLeBroadcastAssistant; + private LocalBluetoothLeBroadcastMetadata mLocalBroadcastMetadata; private Executor mExecutor; private int mSourceId; @@ -183,6 +189,7 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment mCachedDevice = getCachedDevice(mDeviceAddress); mLeBroadcastAssistant = getLeBroadcastAssistant(); mExecutor = Executors.newSingleThreadExecutor(); + mLocalBroadcastMetadata = new LocalBluetoothLeBroadcastMetadata(); super.onAttach(context); if (mCachedDevice == null || mLeBroadcastAssistant == null) { @@ -229,6 +236,34 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment } } + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + Log.d(TAG, "onActivityResult: " + requestCode + ", resultCode: " + resultCode); + if (requestCode == REQUEST_SCAN_BT_BROADCAST_QR_CODE) { + if (resultCode == Activity.RESULT_OK) { + + //Get BroadcastMetadata + String broadcastMetadata = data.getStringExtra( + QrCodeScanModeFragment.KEY_BROADCAST_METADATA); + BluetoothLeBroadcastMetadata source = convertToBroadcastMetadata(broadcastMetadata); + + if (source != null) { + Log.d(TAG, "onActivityResult source Id = " + source.getBroadcastId()); + //Create preference for the broadcast source + updateListCategoryFromBroadcastMetadata(source, false); + //Add Source + addSource(mBroadcastSourceListCategory.findPreference( + Integer.toString(source.getBroadcastId()))); + } else { + Toast.makeText(getContext(), + R.string.find_broadcast_join_broadcast_error, Toast.LENGTH_SHORT).show(); + return; + } + } + } + } + @VisibleForTesting void finishFragmentIfNecessary() { if (mCachedDevice.getBondState() == BOND_NONE) { @@ -467,4 +502,8 @@ public class BluetoothFindBroadcastsFragment extends RestrictedDashboardFragment public void setSourceId(int sourceId) { mSourceId = sourceId; } + + private BluetoothLeBroadcastMetadata convertToBroadcastMetadata(String qrCodeString) { + return mLocalBroadcastMetadata.convertToBroadcastMetadata(qrCodeString); + } } diff --git a/src/com/android/settings/bluetooth/BluetoothFindBroadcastsHeaderController.java b/src/com/android/settings/bluetooth/BluetoothFindBroadcastsHeaderController.java index 1282abda18e..d34476bada5 100644 --- a/src/com/android/settings/bluetooth/BluetoothFindBroadcastsHeaderController.java +++ b/src/com/android/settings/bluetooth/BluetoothFindBroadcastsHeaderController.java @@ -137,7 +137,8 @@ public class BluetoothFindBroadcastsHeaderController extends BluetoothDetailsCon .putExtra(BluetoothBroadcastUtils.EXTRA_BLUETOOTH_SINK_IS_GROUP, true) .putExtra(BluetoothBroadcastUtils.EXTRA_BLUETOOTH_DEVICE_SINK, mCachedDevice.getDevice()); - mContext.startActivity(intent); + mBluetoothFindBroadcastsFragment.startActivityForResult(intent, + BluetoothFindBroadcastsFragment.REQUEST_SCAN_BT_BROADCAST_QR_CODE); } @Override diff --git a/src/com/android/settings/bluetooth/QrCodeScanModeController.java b/src/com/android/settings/bluetooth/QrCodeScanModeController.java deleted file mode 100644 index 4504b4b71aa..00000000000 --- a/src/com/android/settings/bluetooth/QrCodeScanModeController.java +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.settings.bluetooth; - -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothLeBroadcastMetadata; -import android.content.Context; -import android.util.Log; - -import com.android.settingslib.bluetooth.BluetoothUtils; -import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; -import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant; -import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastMetadata; -import com.android.settingslib.bluetooth.LocalBluetoothManager; -import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; - -public class QrCodeScanModeController { - - private static final boolean DEBUG = BluetoothUtils.D; - private static final String TAG = "QrCodeScanModeController"; - - private LocalBluetoothLeBroadcastMetadata mLocalBroadcastMetadata; - private LocalBluetoothLeBroadcastAssistant mLocalBroadcastAssistant; - private LocalBluetoothManager mLocalBluetoothManager; - private LocalBluetoothProfileManager mProfileManager; - - public QrCodeScanModeController(Context context) { - if (DEBUG) { - Log.d(TAG, "QrCodeScanModeController constructor."); - } - mLocalBluetoothManager = Utils.getLocalBtManager(context); - mProfileManager = mLocalBluetoothManager.getProfileManager(); - mLocalBroadcastMetadata = new LocalBluetoothLeBroadcastMetadata(); - CachedBluetoothDeviceManager cachedDeviceManager = new CachedBluetoothDeviceManager(context, - mLocalBluetoothManager); - mLocalBroadcastAssistant = new LocalBluetoothLeBroadcastAssistant(context, - cachedDeviceManager, mProfileManager); - } - - private BluetoothLeBroadcastMetadata convertToBroadcastMetadata(String qrCodeString) { - return mLocalBroadcastMetadata.convertToBroadcastMetadata(qrCodeString); - } - - public void addSource(BluetoothDevice sink, String sourceMetadata, - boolean isGroupOp) { - mLocalBroadcastAssistant.addSource(sink, - convertToBroadcastMetadata(sourceMetadata), isGroupOp); - } -} diff --git a/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java b/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java index 767461bba7e..4baaef4ea3f 100644 --- a/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java +++ b/src/com/android/settings/bluetooth/QrCodeScanModeFragment.java @@ -16,9 +16,11 @@ package com.android.settings.bluetooth; +import android.app.Activity; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothDevice; import android.content.Context; +import android.content.Intent; import android.graphics.Matrix; import android.graphics.Outline; import android.graphics.Rect; @@ -67,13 +69,14 @@ public class QrCodeScanModeFragment extends InstrumentedFragment implements private static final Duration VIBRATE_DURATION_QR_CODE_RECOGNITION = Duration.ofMillis(3); + public static final String KEY_BROADCAST_METADATA = "key_broadcast_metadata"; + private boolean mIsGroupOp; private int mCornerRadius; private BluetoothDevice mSink; private String mBroadcastMetadata; private Context mContext; private QrCamera mCamera; - private QrCodeScanModeController mController; private TextureView mTextureView; private TextView mSummary; private TextView mErrorMessage; @@ -87,7 +90,6 @@ public class QrCodeScanModeFragment extends InstrumentedFragment implements public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mContext = getContext(); - mController = new QrCodeScanModeController(mContext); } @Override @@ -215,10 +217,10 @@ public class QrCodeScanModeFragment extends InstrumentedFragment implements break; case MESSAGE_SCAN_BROADCAST_SUCCESS: - /* TODO(b/265281156) : Move the logic to BluetoothFindBroadcastsFragment. - * We only pass the QR code string to the previous page. - */ - mController.addSource(mSink, mBroadcastMetadata, mIsGroupOp); + Log.d(TAG, "scan success"); + final Intent resultIntent = new Intent(); + resultIntent.putExtra(KEY_BROADCAST_METADATA, mBroadcastMetadata); + getActivity().setResult(Activity.RESULT_OK, resultIntent); notifyUserForQrCodeRecognition(); break; default: From b9f6bb7958d98dbe52c46602810a349c9a207f04 Mon Sep 17 00:00:00 2001 From: Zoey Chen Date: Thu, 16 Mar 2023 18:40:08 +0000 Subject: [PATCH 10/14] [Settings] Fix the inconsistent data/entity when switch the app/fragment Bug: 271524675 Bug: 273825889 Test: local test Change-Id: I7ec6d824c5154422aaad056dc3f4dcd365fef5e1 --- .../network/MobileNetworkRepository.java | 412 +++++++++++------- 1 file changed, 254 insertions(+), 158 deletions(-) diff --git a/src/com/android/settings/network/MobileNetworkRepository.java b/src/com/android/settings/network/MobileNetworkRepository.java index f07a3b73779..1e57c4846bf 100644 --- a/src/com/android/settings/network/MobileNetworkRepository.java +++ b/src/com/android/settings/network/MobileNetworkRepository.java @@ -20,6 +20,7 @@ import static android.telephony.UiccSlotInfo.CARD_STATE_INFO_PRESENT; import static com.android.internal.telephony.TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED; +import android.annotation.NonNull; import android.app.settings.SettingsEnums; import android.content.BroadcastReceiver; import android.content.Context; @@ -56,10 +57,12 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.stream.Collectors; +import androidx.annotation.GuardedBy; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.LifecycleOwner; @@ -72,14 +75,17 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static ExecutorService sExecutor = Executors.newSingleThreadExecutor(); - private static Map sCacheSubscriptionInfoEntityMap = + private static Map sCacheSubscriptionInfoEntityMap = new ArrayMap<>(); - private static Map sCacheMobileNetworkInfoEntityMap = + private static Map sCacheMobileNetworkInfoEntityMap = new ArrayMap<>(); - private static Map sCacheUiccInfoEntityMap = new ArrayMap<>(); + private static Map sCacheUiccInfoEntityMap = new ArrayMap<>(); + private static Collection sCallbacks = new CopyOnWriteArrayList<>(); + private static final Object sInstanceLock = new Object(); + @GuardedBy("sInstanceLock") + private static MobileNetworkRepository sInstance; private SubscriptionManager mSubscriptionManager; - private TelephonyManager mTelephonyManager; private MobileNetworkDatabase mMobileNetworkDatabase; private SubscriptionInfoDao mSubscriptionInfoDao; private UiccInfoDao mUiccInfoDao; @@ -88,7 +94,6 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions private List mActiveSubInfoEntityList = new ArrayList<>(); private List mUiccInfoEntityList = new ArrayList<>(); private List mMobileNetworkInfoEntityList = new ArrayList<>(); - private MobileNetworkCallback mCallback; private Context mContext; private AirplaneModeObserver mAirplaneModeObserver; private Uri mAirplaneModeSettingUri; @@ -100,35 +105,34 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions private int mCardState = UiccSlotInfo.CARD_STATE_INFO_ABSENT; private int mPortIndex = TelephonyManager.INVALID_PORT_INDEX; private int mCardId = TelephonyManager.UNINITIALIZED_CARD_ID; - private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; private boolean mIsEuicc = false; private boolean mIsRemovable = false; private boolean mIsActive = false; private Map mSubscriptionInfoMap = new ArrayMap<>(); private Map mTelephonyManagerMap = new HashMap<>(); private Map mTelephonyCallbackMap = new HashMap<>(); + private BroadcastReceiver mDataSubscriptionChangedReceiver = null; - public static MobileNetworkRepository create(Context context, - MobileNetworkCallback mobileNetworkCallback) { - return new MobileNetworkRepository(context, mobileNetworkCallback, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); + @NonNull + public static MobileNetworkRepository getInstance(Context context) { + synchronized (sInstanceLock) { + if (sInstance != null) { + return sInstance; + } + if (DEBUG) { + Log.d(TAG, "Init the instance."); + } + sInstance = new MobileNetworkRepository(context); + return sInstance; + } } - public static MobileNetworkRepository createBySubId(Context context, - MobileNetworkCallback mobileNetworkCallback, int subId) { - return new MobileNetworkRepository(context, mobileNetworkCallback, subId); - } - - private MobileNetworkRepository(Context context, MobileNetworkCallback mobileNetworkCallback, - int subId) { - mSubId = subId; + private MobileNetworkRepository(Context context) { mContext = context; mMobileNetworkDatabase = MobileNetworkDatabase.getInstance(context); mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); - mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_MOBILE_NETWORK_DB_CREATED, - subId); + mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_MOBILE_NETWORK_DB_CREATED); mSubscriptionManager = context.getSystemService(SubscriptionManager.class); - mCallback = mobileNetworkCallback; mSubscriptionInfoDao = mMobileNetworkDatabase.mSubscriptionInfoDao(); mUiccInfoDao = mMobileNetworkDatabase.mUiccInfoDao(); mMobileNetworkInfoDao = mMobileNetworkDatabase.mMobileNetworkInfoDao(); @@ -138,6 +142,8 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions mFilter.addAction(SubscriptionManager.ACTION_DEFAULT_SUBSCRIPTION_CHANGED); mFilter.addAction(ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); mFilter.addAction(SubscriptionManager.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED); + mDataSubscriptionChangedReceiver = new DataSubscriptionChangedReceiver(); + mContext.registerReceiver(mDataSubscriptionChangedReceiver, mFilter); } private class AirplaneModeObserver extends ContentObserver { @@ -157,56 +163,98 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions @Override public void onChange(boolean selfChange, Uri uri) { if (uri.equals(mAirplaneModeSettingUri)) { - mCallback.onAirplaneModeChanged(isAirplaneModeOn()); + boolean isAirplaneModeOn = isAirplaneModeOn(); + for (MobileNetworkCallback callback : sCallbacks) { + callback.onAirplaneModeChanged(isAirplaneModeOn); + } } } } - private final BroadcastReceiver mDataSubscriptionChangedReceiver = new BroadcastReceiver() { + private class DataSubscriptionChangedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { onSubscriptionsChanged(); } - }; + } - public void addRegister(LifecycleOwner lifecycleOwner) { + /** + * Register all callbacks and listener. + * + * @param lifecycleOwner The lifecycle owner. + * @param mobileNetworkCallback A callback to receive all MobileNetwork's changes. + * @param subId The subscription ID to register relevant changes and listener for specific + * subscription. + */ + public void addRegister(LifecycleOwner lifecycleOwner, + MobileNetworkCallback mobileNetworkCallback, int subId) { + sCallbacks.add(mobileNetworkCallback); mSubscriptionManager.addOnSubscriptionsChangedListener(mContext.getMainExecutor(), this); mAirplaneModeObserver.register(mContext); - mContext.registerReceiver(mDataSubscriptionChangedReceiver, mFilter); observeAllSubInfo(lifecycleOwner); observeAllUiccInfo(lifecycleOwner); observeAllMobileNetworkInfo(lifecycleOwner); + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + addRegisterBySubId(subId); + createTelephonyManagerBySubId(subId); + } } private void addRegisterBySubId(int subId) { - if (!mTelephonyCallbackMap.containsKey(subId) || !mTelephonyManagerMap.containsKey(subId)) { - PhoneCallStateTelephonyCallback - telephonyCallback = new PhoneCallStateTelephonyCallback(); - mTelephonyManager.registerTelephonyCallback(mContext.getMainExecutor(), - telephonyCallback); - mTelephonyCallbackMap.put(subId, telephonyCallback); - mTelephonyManagerMap.put(subId, mTelephonyManager); - } - if (!mDataContentObserverMap.containsKey(subId)) { - MobileDataContentObserver dataContentObserver = new MobileDataContentObserver( - new Handler(Looper.getMainLooper())); - dataContentObserver.register(mContext, subId); - dataContentObserver.setOnMobileDataChangedListener(() -> { - sExecutor.execute(() -> { - insertMobileNetworkInfo(mContext, String.valueOf(subId)); - }); + MobileDataContentObserver dataContentObserver = new MobileDataContentObserver( + new Handler(Looper.getMainLooper())); + dataContentObserver.setOnMobileDataChangedListener(() -> { + sExecutor.execute(() -> { + insertMobileNetworkInfo(mContext, subId, + getTelephonyManagerBySubId(mContext, subId)); }); - mDataContentObserverMap.put(subId, dataContentObserver); + }); + dataContentObserver.register(mContext, subId); + mDataContentObserverMap.put(subId, dataContentObserver); + } + + private void createTelephonyManagerBySubId(int subId) { + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + return; } + PhoneCallStateTelephonyCallback + telephonyCallback = new PhoneCallStateTelephonyCallback(); + TelephonyManager telephonyManager = mContext.getSystemService( + TelephonyManager.class).createForSubscriptionId(subId); + telephonyManager.registerTelephonyCallback(mContext.getMainExecutor(), + telephonyCallback); + mTelephonyCallbackMap.put(subId, telephonyCallback); + mTelephonyManagerMap.put(subId, telephonyManager); + } + + private TelephonyManager getTelephonyManagerBySubId(Context context, int subId) { + TelephonyManager telephonyManager = mTelephonyManagerMap.get(subId); + if (telephonyManager != null) { + return telephonyManager; + } + + if (context != null) { + telephonyManager = context.getSystemService(TelephonyManager.class); + if (telephonyManager != null) { + telephonyManager = telephonyManager.createForSubscriptionId(subId); + } else if (DEBUG) { + Log.d(TAG, "Can not get TelephonyManager for subId " + subId); + } + } + + return telephonyManager; + } private void removerRegisterBySubId(int subId) { if (mTelephonyCallbackMap.containsKey(subId)) { - TelephonyManager tm = mTelephonyManagerMap.get(subId); - PhoneCallStateTelephonyCallback callback = mTelephonyCallbackMap.get(subId); - if (callback != null) { - tm.unregisterTelephonyCallback(callback); - mTelephonyCallbackMap.remove(subId); + TelephonyManager telephonyManager = getTelephonyManagerBySubId(mContext, subId); + if (telephonyManager != null) { + PhoneCallStateTelephonyCallback callback = mTelephonyCallbackMap.get(subId); + if (callback != null) { + telephonyManager.unregisterTelephonyCallback(callback); + mTelephonyCallbackMap.remove(subId); + } } } if (mDataContentObserverMap.containsKey(subId)) { @@ -215,25 +263,43 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions } } - public void removeRegister() { - mSubscriptionManager.removeOnSubscriptionsChangedListener(this); - mAirplaneModeObserver.unRegister(mContext); - if (mDataSubscriptionChangedReceiver != null) { - mContext.unregisterReceiver(mDataSubscriptionChangedReceiver); - } - mDataContentObserverMap.forEach((id, observer) -> { - observer.unRegister(mContext); - }); - mDataContentObserverMap.clear(); - - mTelephonyManagerMap.forEach((id, manager) -> { - TelephonyCallback callback = mTelephonyCallbackMap.get(manager.getSubscriptionId()); - if (callback != null) { - manager.unregisterTelephonyCallback(callback); + public void removeRegister(MobileNetworkCallback mobileNetworkCallback) { + sCallbacks.remove(mobileNetworkCallback); + if (sCallbacks.isEmpty()) { + mSubscriptionManager.removeOnSubscriptionsChangedListener(this); + mAirplaneModeObserver.unRegister(mContext); + if (mDataSubscriptionChangedReceiver != null) { + mContext.unregisterReceiver(mDataSubscriptionChangedReceiver); + mDataSubscriptionChangedReceiver = null; } - }); - mTelephonyCallbackMap.clear(); - mTelephonyManagerMap.clear(); + mDataContentObserverMap.forEach((id, observer) -> { + observer.unRegister(mContext); + }); + mDataContentObserverMap.clear(); + + mTelephonyManagerMap.forEach((id, manager) -> { + TelephonyCallback callback = mTelephonyCallbackMap.get(id); + if (callback != null) { + manager.unregisterTelephonyCallback(callback); + } + }); + mTelephonyCallbackMap.clear(); + mTelephonyManagerMap.clear(); + } + } + + public void updateEntity() { + // Check the latest state after back to the UI. + if (sCacheSubscriptionInfoEntityMap != null || !sCacheSubscriptionInfoEntityMap.isEmpty()) { + sExecutor.execute(() -> { + onSubscriptionsChanged(); + }); + } + + boolean isAirplaneModeOn = isAirplaneModeOn(); + for (MobileNetworkCallback callback : sCallbacks) { + callback.onAirplaneModeChanged(isAirplaneModeOn); + } } private void observeAllSubInfo(LifecycleOwner lifecycleOwner) { @@ -284,18 +350,6 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions return mMobileNetworkInfoDao.queryMobileNetworkInfoBySubId(subId); } - public int getSubInfosCount() { - return mSubscriptionInfoDao.count(); - } - - public int getUiccInfosCount() { - return mUiccInfoDao.count(); - } - - public int getMobileNetworkInfosCount() { - return mMobileNetworkInfoDao.count(); - } - private void getUiccInfoBySubscriptionInfo(UiccSlotInfo[] uiccSlotInfos, SubscriptionInfo subInfo) { for (int i = 0; i < uiccSlotInfos.length; i++) { @@ -317,7 +371,7 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions mPortIndex = portInfo.getPortIndex(); } else if (DEBUG) { Log.d(TAG, "Can not get port index and physicalSlotIndex for subId " - + mSubId); + + subInfo.getSubscriptionId()); } }); if (mPhysicalSlotIndex != SubscriptionManager.INVALID_SIM_SLOT_INDEX) { @@ -334,70 +388,82 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions private void onAvailableSubInfoChanged( List availableSubInfoEntityList) { - mAvailableSubInfoEntityList = availableSubInfoEntityList; - mActiveSubInfoEntityList = mAvailableSubInfoEntityList.stream() - .filter(SubscriptionInfoEntity::isActiveSubscription) - .filter(SubscriptionInfoEntity::isSubscriptionVisible) - .collect(Collectors.toList()); + mAvailableSubInfoEntityList = new ArrayList<>(availableSubInfoEntityList); if (DEBUG) { Log.d(TAG, "onAvailableSubInfoChanged, availableSubInfoEntityList = " + availableSubInfoEntityList); } - mCallback.onAvailableSubInfoChanged(availableSubInfoEntityList); + for (MobileNetworkCallback callback : sCallbacks) { + callback.onAvailableSubInfoChanged(availableSubInfoEntityList); + } mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_MOBILE_NETWORK_DB_NOTIFY_SUB_INFO_IS_CHANGED, 0); - setActiveSubInfoList(mActiveSubInfoEntityList); + onActiveSubInfoListChanged(mAvailableSubInfoEntityList); } - private void setActiveSubInfoList(List activeSubInfoEntityList) { + private void onActiveSubInfoListChanged( + List availableSubInfoEntityList) { + mActiveSubInfoEntityList = availableSubInfoEntityList.stream() + .filter(SubscriptionInfoEntity::isActiveSubscription) + .filter(SubscriptionInfoEntity::isSubscriptionVisible) + .collect(Collectors.toList()); if (DEBUG) { - Log.d(TAG, - "onActiveSubInfoChanged, activeSubInfoEntityList = " + activeSubInfoEntityList); + Log.d(TAG, "onActiveSubInfoChanged, activeSubInfoEntityList = " + + mActiveSubInfoEntityList); + } + List activeSubInfoEntityList = new ArrayList<>( + mActiveSubInfoEntityList); + for (MobileNetworkCallback callback : sCallbacks) { + callback.onActiveSubInfoChanged(activeSubInfoEntityList); } - mCallback.onActiveSubInfoChanged(mActiveSubInfoEntityList); } private void onAllUiccInfoChanged(List uiccInfoEntityList) { - mUiccInfoEntityList = uiccInfoEntityList; - mCallback.onAllUiccInfoChanged(uiccInfoEntityList); + mUiccInfoEntityList = new ArrayList<>(uiccInfoEntityList); + for (MobileNetworkCallback callback : sCallbacks) { + callback.onAllUiccInfoChanged(uiccInfoEntityList); + } mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_MOBILE_NETWORK_DB_NOTIFY_UICC_INFO_IS_CHANGED, 0); } private void onAllMobileNetworkInfoChanged( List mobileNetworkInfoEntityList) { - mMobileNetworkInfoEntityList = mobileNetworkInfoEntityList; - mCallback.onAllMobileNetworkInfoChanged(mobileNetworkInfoEntityList); + mMobileNetworkInfoEntityList = new ArrayList<>(mobileNetworkInfoEntityList); + for (MobileNetworkCallback callback : sCallbacks) { + callback.onAllMobileNetworkInfoChanged(mobileNetworkInfoEntityList); + } mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_MOBILE_NETWORK_DB_NOTIFY_MOBILE_NETWORK_INFO_IS_CHANGED, 0); } - public void insertSubInfo(Context context, SubscriptionInfo info) { + private void insertSubInfo(Context context, SubscriptionInfo info) { + int subId = info.getSubscriptionId(); + createTelephonyManagerBySubId(subId); + TelephonyManager telephonyManager = getTelephonyManagerBySubId(context, subId); SubscriptionInfoEntity subInfoEntity = - convertToSubscriptionInfoEntity(context, info); - String subId = String.valueOf(mSubId); + convertToSubscriptionInfoEntity(context, info, telephonyManager); if (subInfoEntity != null) { if (!sCacheSubscriptionInfoEntityMap.containsKey(subId) || (sCacheSubscriptionInfoEntityMap.get(subId) != null && !sCacheSubscriptionInfoEntityMap.get(subId).equals(subInfoEntity))) { sCacheSubscriptionInfoEntityMap.put(subId, subInfoEntity); if (DEBUG) { - Log.d(TAG, "convert subId " + subId + "to SubscriptionInfoEntity: " + Log.d(TAG, "Convert subId " + subId + " to SubscriptionInfoEntity: " + subInfoEntity); } mMobileNetworkDatabase.insertSubsInfo(subInfoEntity); - addRegisterBySubId(mSubId); - insertUiccInfo(subId); - insertMobileNetworkInfo(context, subId); mMetricsFeatureProvider.action(mContext, - SettingsEnums.ACTION_MOBILE_NETWORK_DB_INSERT_SUB_INFO, mSubId); - } else if (DEBUG) { - Log.d(TAG, "Can not insert subInfo, the entity is null"); + SettingsEnums.ACTION_MOBILE_NETWORK_DB_INSERT_SUB_INFO, subId); + insertUiccInfo(subId, telephonyManager); + insertMobileNetworkInfo(context, subId, telephonyManager); } + } else if (DEBUG) { + Log.d(TAG, "Can not insert subInfo, the entity is null"); } } - public void deleteAllInfoBySubId(String subId) { + private void deleteAllInfoBySubId(String subId) { if (DEBUG) { Log.d(TAG, "deleteAllInfoBySubId, subId = " + subId); } @@ -412,20 +478,23 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions removerRegisterBySubId(id); mSubscriptionInfoMap.remove(id); mTelephonyManagerMap.remove(id); - sCacheSubscriptionInfoEntityMap.remove(subId); - sCacheUiccInfoEntityMap.remove(subId); - sCacheMobileNetworkInfoEntityMap.remove(subId); + sCacheSubscriptionInfoEntityMap.remove(id); + sCacheUiccInfoEntityMap.remove(id); + sCacheMobileNetworkInfoEntityMap.remove(id); mMetricsFeatureProvider.action(mContext, SettingsEnums.ACTION_MOBILE_NETWORK_DB_DELETE_DATA, id); } - public SubscriptionInfoEntity convertToSubscriptionInfoEntity(Context context, - SubscriptionInfo subInfo) { - mSubId = subInfo.getSubscriptionId(); - mTelephonyManager = context.getSystemService( - TelephonyManager.class).createForSubscriptionId(mSubId); - - UiccSlotInfo[] uiccSlotInfos = mTelephonyManager.getUiccSlotsInfo(); + private SubscriptionInfoEntity convertToSubscriptionInfoEntity(Context context, + SubscriptionInfo subInfo, TelephonyManager telephonyManager) { + int subId = subInfo.getSubscriptionId(); + if (telephonyManager == null) { + if (DEBUG) { + Log.d(TAG, "Can not get TelephonyManager for subId " + subId); + } + return null; + } + UiccSlotInfo[] uiccSlotInfos = telephonyManager.getUiccSlotsInfo(); if (uiccSlotInfos == null || uiccSlotInfos.length == 0) { if (DEBUG) { Log.d(TAG, "uiccSlotInfos = null or empty"); @@ -435,10 +504,10 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions getUiccInfoBySubscriptionInfo(uiccSlotInfos, subInfo); SubscriptionInfo firstRemovableSubInfo = SubscriptionUtil.getFirstRemovableSubscription( context); - if(DEBUG){ - Log.d(TAG, "convert subscriptionInfo to entity for subId = " + mSubId); + if (DEBUG) { + Log.d(TAG, "convert subscriptionInfo to entity for subId = " + subId); } - return new SubscriptionInfoEntity(String.valueOf(mSubId), + return new SubscriptionInfoEntity(String.valueOf(subId), subInfo.getSimSlotIndex(), subInfo.getCarrierId(), subInfo.getDisplayName().toString(), subInfo.getCarrierName() != null ? subInfo.getCarrierName().toString() : "", @@ -451,23 +520,23 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions SubscriptionUtil.isSubscriptionVisible(mSubscriptionManager, context, subInfo), SubscriptionUtil.getFormattedPhoneNumber(context, subInfo), firstRemovableSubInfo == null ? false - : firstRemovableSubInfo.getSubscriptionId() == mSubId, - String.valueOf(SubscriptionUtil.getDefaultSimConfig(context, mSubId)), - SubscriptionUtil.isDefaultSubscription(context, mSubId), - mSubscriptionManager.isValidSubscriptionId(mSubId), - mSubscriptionManager.isUsableSubscriptionId(mSubId), - mSubscriptionManager.isActiveSubscriptionId(mSubId), + : firstRemovableSubInfo.getSubscriptionId() == subId, + String.valueOf(SubscriptionUtil.getDefaultSimConfig(context, subId)), + SubscriptionUtil.isDefaultSubscription(context, subId), + mSubscriptionManager.isValidSubscriptionId(subId), + mSubscriptionManager.isUsableSubscriptionId(subId), + mSubscriptionManager.isActiveSubscriptionId(subId), true /*availableSubInfo*/, - mSubscriptionManager.getDefaultVoiceSubscriptionId() == mSubId, - mSubscriptionManager.getDefaultSmsSubscriptionId() == mSubId, - mSubscriptionManager.getDefaultDataSubscriptionId() == mSubId, - mSubscriptionManager.getDefaultSubscriptionId() == mSubId, - mSubscriptionManager.getActiveDataSubscriptionId() == mSubId); + mSubscriptionManager.getDefaultVoiceSubscriptionId() == subId, + mSubscriptionManager.getDefaultSmsSubscriptionId() == subId, + mSubscriptionManager.getDefaultDataSubscriptionId() == subId, + mSubscriptionManager.getDefaultSubscriptionId() == subId, + mSubscriptionManager.getActiveDataSubscriptionId() == subId); } } - public void insertUiccInfo(String subId) { - UiccInfoEntity uiccInfoEntity = convertToUiccInfoEntity(); + private void insertUiccInfo(int subId, TelephonyManager telephonyManager) { + UiccInfoEntity uiccInfoEntity = convertToUiccInfoEntity(subId, telephonyManager); if (DEBUG) { Log.d(TAG, "uiccInfoEntity = " + uiccInfoEntity); } @@ -476,51 +545,76 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions sCacheUiccInfoEntityMap.put(subId, uiccInfoEntity); mMobileNetworkDatabase.insertUiccInfo(uiccInfoEntity); mMetricsFeatureProvider.action(mContext, - SettingsEnums.ACTION_MOBILE_NETWORK_DB_INSERT_UICC_INFO, - Integer.parseInt(subId)); + SettingsEnums.ACTION_MOBILE_NETWORK_DB_INSERT_UICC_INFO, subId); } } - public void insertMobileNetworkInfo(Context context, String subId) { - MobileNetworkInfoEntity mobileNetworkInfoEntity = convertToMobileNetworkInfoEntity(context); + private void insertMobileNetworkInfo(Context context, int subId, + TelephonyManager telephonyManager) { + MobileNetworkInfoEntity mobileNetworkInfoEntity = convertToMobileNetworkInfoEntity(context, + subId, telephonyManager); + if (DEBUG) { - Log.d(TAG, "mobileNetworkInfoEntity = " + mobileNetworkInfoEntity); + Log.d(TAG, "insertMobileNetworkInfo, mobileNetworkInfoEntity = " + + mobileNetworkInfoEntity); } + + if (mobileNetworkInfoEntity == null) { + return; + } + if (!sCacheMobileNetworkInfoEntityMap.containsKey(subId) || !sCacheMobileNetworkInfoEntityMap.get(subId).equals(mobileNetworkInfoEntity)) { sCacheMobileNetworkInfoEntityMap.put(subId, mobileNetworkInfoEntity); mMobileNetworkDatabase.insertMobileNetworkInfo(mobileNetworkInfoEntity); mMetricsFeatureProvider.action(mContext, - SettingsEnums.ACTION_MOBILE_NETWORK_DB_INSERT_MOBILE_NETWORK_INFO, - Integer.parseInt(subId)); + SettingsEnums.ACTION_MOBILE_NETWORK_DB_INSERT_MOBILE_NETWORK_INFO, subId); } } - public MobileNetworkInfoEntity convertToMobileNetworkInfoEntity(Context context) { - return new MobileNetworkInfoEntity(String.valueOf(mSubId), - MobileNetworkUtils.isContactDiscoveryEnabled(context, mSubId), - MobileNetworkUtils.isContactDiscoveryVisible(context, mSubId), - mTelephonyManager.isDataEnabled(), - MobileNetworkUtils.isCdmaOptions(context, mSubId), - MobileNetworkUtils.isGsmOptions(context, mSubId), - MobileNetworkUtils.isWorldMode(context, mSubId), - MobileNetworkUtils.shouldDisplayNetworkSelectOptions(context, mSubId), - MobileNetworkUtils.isTdscdmaSupported(context, mSubId), + private MobileNetworkInfoEntity convertToMobileNetworkInfoEntity(Context context, int subId, + TelephonyManager telephonyManager) { + boolean isDataEnabled = false; + boolean isDataRoamingEnabled = false; + if (telephonyManager != null) { + isDataEnabled = telephonyManager.isDataEnabled(); + isDataRoamingEnabled = telephonyManager.isDataRoamingEnabled(); + } else if (DEBUG) { + Log.d(TAG, "TelephonyManager is null, subId = " + subId); + } + + return new MobileNetworkInfoEntity(String.valueOf(subId), + MobileNetworkUtils.isContactDiscoveryEnabled(context, subId), + MobileNetworkUtils.isContactDiscoveryVisible(context, subId), + isDataEnabled, + MobileNetworkUtils.isCdmaOptions(context, subId), + MobileNetworkUtils.isGsmOptions(context, subId), + MobileNetworkUtils.isWorldMode(context, subId), + MobileNetworkUtils.shouldDisplayNetworkSelectOptions(context, subId), + MobileNetworkUtils.isTdscdmaSupported(context, subId), MobileNetworkUtils.activeNetworkIsCellular(context), SubscriptionUtil.showToggleForPhysicalSim(mSubscriptionManager), - mTelephonyManager.isDataRoamingEnabled() + isDataRoamingEnabled ); } - private UiccInfoEntity convertToUiccInfoEntity() { - return new UiccInfoEntity(String.valueOf(mSubId), String.valueOf(mPhysicalSlotIndex), - mLogicalSlotIndex, mCardId, mIsEuicc, isMultipleEnabledProfilesSupported(), - mCardState, mIsRemovable, mIsActive, mPortIndex + private UiccInfoEntity convertToUiccInfoEntity(int subId, TelephonyManager telephonyManager) { + return new UiccInfoEntity(String.valueOf(subId), String.valueOf(mPhysicalSlotIndex), + mLogicalSlotIndex, mCardId, mIsEuicc, + isMultipleEnabledProfilesSupported(telephonyManager), mCardState, mIsRemovable, + mIsActive, mPortIndex ); } - private boolean isMultipleEnabledProfilesSupported() { - List cardInfos = mTelephonyManager.getUiccCardsInfo(); + private boolean isMultipleEnabledProfilesSupported(TelephonyManager telephonyManager) { + if (telephonyManager == null) { + if (DEBUG) { + Log.d(TAG, "TelephonyManager is null"); + } + return false; + } + + List cardInfos = telephonyManager.getUiccCardsInfo(); if (cardInfos == null) { if (DEBUG) { Log.d(TAG, "UICC card info list is empty."); @@ -574,7 +668,7 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions // the database, if the subInfo is not existed in the new list, delete it // from the database. for (SubscriptionInfoEntity info : availableInfoArray) { - if (sCacheSubscriptionInfoEntityMap.containsKey(info.subId)) { + if (sCacheSubscriptionInfoEntityMap.containsKey(info.getSubId())) { deleteAllInfoBySubId(info.subId); } } @@ -593,7 +687,7 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions } continue; } - mSubscriptionInfoMap.put(mSubId, subInfo); + mSubscriptionInfoMap.put(subInfo.getSubscriptionId(), subInfo); insertSubInfo(mContext, subInfo); } } @@ -610,7 +704,9 @@ public class MobileNetworkRepository extends SubscriptionManager.OnSubscriptions @Override public void onCallStateChanged(int state) { - mCallback.onCallStateChanged(state); + for (MobileNetworkCallback callback : sCallbacks) { + callback.onCallStateChanged(state); + } } } From db02f10b07a2ad1b4683201e3faf7fba7481d482 Mon Sep 17 00:00:00 2001 From: Zoey Chen Date: Thu, 16 Mar 2023 18:40:59 +0000 Subject: [PATCH 11/14] [Settings] update the db list when back to UI Bug: 271524675 Test: local test Change-Id: I26c7d64e6f040c62c9efb1438efe328f5744fa02 --- .../network/InternetPreferenceController.java | 8 +++++--- .../network/MobileNetworkSummaryController.java | 10 ++++++---- .../network/NetworkProviderCallsSmsController.java | 10 ++++++---- .../network/NetworkProviderSimListController.java | 9 +++++---- .../telephony/ConvertToEsimPreferenceController.java | 7 ++++--- .../telephony/DefaultSubscriptionController.java | 10 ++++------ .../telephony/MobileDataPreferenceController.java | 10 ++++------ .../network/telephony/MobileNetworkSettings.java | 11 +++++++---- .../telephony/RoamingPreferenceController.java | 7 ++++--- .../network/MobileNetworkSummaryControllerTest.java | 7 ++++--- 10 files changed, 49 insertions(+), 40 deletions(-) diff --git a/src/com/android/settings/network/InternetPreferenceController.java b/src/com/android/settings/network/InternetPreferenceController.java index ad1a5f04d56..898585c1b21 100644 --- a/src/com/android/settings/network/InternetPreferenceController.java +++ b/src/com/android/settings/network/InternetPreferenceController.java @@ -101,7 +101,7 @@ public class InternetPreferenceController extends AbstractPreferenceController i mInternetUpdater = new InternetUpdater(context, lifecycle, this); mInternetType = mInternetUpdater.getInternetType(); mLifecycleOwner = lifecycleOwner; - mMobileNetworkRepository = MobileNetworkRepository.create(context, this); + mMobileNetworkRepository = MobileNetworkRepository.getInstance(context); lifecycle.addObserver(this); } @@ -156,14 +156,16 @@ public class InternetPreferenceController extends AbstractPreferenceController i /** @OnLifecycleEvent(ON_RESUME) */ @OnLifecycleEvent(ON_RESUME) public void onResume() { - mMobileNetworkRepository.addRegister(mLifecycleOwner); + mMobileNetworkRepository.addRegister(mLifecycleOwner, this, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mMobileNetworkRepository.updateEntity(); mSummaryHelper.register(true); } /** @OnLifecycleEvent(ON_PAUSE) */ @OnLifecycleEvent(ON_PAUSE) public void onPause() { - mMobileNetworkRepository.removeRegister(); + mMobileNetworkRepository.removeRegister(this); mSummaryHelper.register(false); } diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.java b/src/com/android/settings/network/MobileNetworkSummaryController.java index 449323dd4cb..99a2731e916 100644 --- a/src/com/android/settings/network/MobileNetworkSummaryController.java +++ b/src/com/android/settings/network/MobileNetworkSummaryController.java @@ -22,6 +22,7 @@ import static androidx.lifecycle.Lifecycle.Event.ON_RESUME; import android.content.Context; import android.content.Intent; import android.os.UserManager; +import android.telephony.SubscriptionManager; import android.telephony.euicc.EuiccManager; import android.util.Log; @@ -87,7 +88,7 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController mMetricsFeatureProvider = FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(); mUserManager = context.getSystemService(UserManager.class); mLifecycleOwner = lifecycleOwner; - mMobileNetworkRepository = MobileNetworkRepository.create(context, this); + mMobileNetworkRepository = MobileNetworkRepository.getInstance(context); mIsAirplaneModeOn = mMobileNetworkRepository.isAirplaneModeOn(); if (lifecycle != null) { lifecycle.addObserver(this); @@ -96,13 +97,14 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController @OnLifecycleEvent(ON_RESUME) public void onResume() { - mMobileNetworkRepository.addRegister(mLifecycleOwner); - update(); + mMobileNetworkRepository.addRegister(mLifecycleOwner, this, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mMobileNetworkRepository.updateEntity(); } @OnLifecycleEvent(ON_PAUSE) public void onPause() { - mMobileNetworkRepository.removeRegister(); + mMobileNetworkRepository.removeRegister(this); } @Override diff --git a/src/com/android/settings/network/NetworkProviderCallsSmsController.java b/src/com/android/settings/network/NetworkProviderCallsSmsController.java index ced2b8acfe5..0c71aa71595 100644 --- a/src/com/android/settings/network/NetworkProviderCallsSmsController.java +++ b/src/com/android/settings/network/NetworkProviderCallsSmsController.java @@ -21,6 +21,7 @@ import static androidx.lifecycle.Lifecycle.Event; import android.content.Context; import android.os.UserManager; import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; import android.view.View; @@ -71,7 +72,7 @@ public class NetworkProviderCallsSmsController extends AbstractPreferenceControl mIsRtlMode = context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; mLifecycleOwner = lifecycleOwner; - mMobileNetworkRepository = MobileNetworkRepository.create(context, this); + mMobileNetworkRepository = MobileNetworkRepository.getInstance(context); if (lifecycle != null) { lifecycle.addObserver(this); } @@ -79,13 +80,14 @@ public class NetworkProviderCallsSmsController extends AbstractPreferenceControl @OnLifecycleEvent(Event.ON_RESUME) public void onResume() { - mMobileNetworkRepository.addRegister(mLifecycleOwner); - update(); + mMobileNetworkRepository.addRegister(mLifecycleOwner, this, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mMobileNetworkRepository.updateEntity(); } @OnLifecycleEvent(Event.ON_PAUSE) public void onPause() { - mMobileNetworkRepository.removeRegister(); + mMobileNetworkRepository.removeRegister(this); } @Override diff --git a/src/com/android/settings/network/NetworkProviderSimListController.java b/src/com/android/settings/network/NetworkProviderSimListController.java index 46249abaf08..db27291bc76 100644 --- a/src/com/android/settings/network/NetworkProviderSimListController.java +++ b/src/com/android/settings/network/NetworkProviderSimListController.java @@ -65,19 +65,20 @@ public class NetworkProviderSimListController extends AbstractPreferenceControll mSubscriptionManager = context.getSystemService(SubscriptionManager.class); mPreferences = new ArrayMap<>(); mLifecycleOwner = lifecycleOwner; - mMobileNetworkRepository = MobileNetworkRepository.create(context, this); + mMobileNetworkRepository = MobileNetworkRepository.getInstance(context); lifecycle.addObserver(this); } @OnLifecycleEvent(ON_RESUME) public void onResume() { - mMobileNetworkRepository.addRegister(mLifecycleOwner); - update(); + mMobileNetworkRepository.addRegister(mLifecycleOwner, this, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mMobileNetworkRepository.updateEntity(); } @OnLifecycleEvent(ON_PAUSE) public void onPause() { - mMobileNetworkRepository.removeRegister(); + mMobileNetworkRepository.removeRegister(this); } @Override diff --git a/src/com/android/settings/network/telephony/ConvertToEsimPreferenceController.java b/src/com/android/settings/network/telephony/ConvertToEsimPreferenceController.java index 46ec61d9f60..b4e768c8f9d 100644 --- a/src/com/android/settings/network/telephony/ConvertToEsimPreferenceController.java +++ b/src/com/android/settings/network/telephony/ConvertToEsimPreferenceController.java @@ -52,7 +52,7 @@ public class ConvertToEsimPreferenceController extends TelephonyBasePreferenceCo LifecycleOwner lifecycleOwner, int subId) { super(context, key); mSubId = subId; - mMobileNetworkRepository = MobileNetworkRepository.createBySubId(context, this, mSubId); + mMobileNetworkRepository = MobileNetworkRepository.getInstance(context); mLifecycleOwner = lifecycleOwner; if (lifecycle != null) { lifecycle.addObserver(this); @@ -66,12 +66,13 @@ public class ConvertToEsimPreferenceController extends TelephonyBasePreferenceCo @OnLifecycleEvent(ON_START) public void onStart() { - mMobileNetworkRepository.addRegister(mLifecycleOwner); + mMobileNetworkRepository.addRegister(mLifecycleOwner, this, mSubId); + mMobileNetworkRepository.updateEntity(); } @OnLifecycleEvent(ON_STOP) public void onStop() { - mMobileNetworkRepository.removeRegister(); + mMobileNetworkRepository.removeRegister(this); } @Override diff --git a/src/com/android/settings/network/telephony/DefaultSubscriptionController.java b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java index 106929b2928..01ec5df549f 100644 --- a/src/com/android/settings/network/telephony/DefaultSubscriptionController.java +++ b/src/com/android/settings/network/telephony/DefaultSubscriptionController.java @@ -75,7 +75,7 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere mManager = context.getSystemService(SubscriptionManager.class); mIsRtlMode = context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; - mMobileNetworkRepository = MobileNetworkRepository.create(context, this); + mMobileNetworkRepository = MobileNetworkRepository.getInstance(context); mLifecycleOwner = lifecycleOwner; if (lifecycle != null) { lifecycle.addObserver(this); @@ -104,13 +104,13 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere @OnLifecycleEvent(ON_RESUME) public void onResume() { - mMobileNetworkRepository.addRegister(mLifecycleOwner); - updateEntries(); + mMobileNetworkRepository.addRegister(mLifecycleOwner, this, getDefaultSubscriptionId()); + mMobileNetworkRepository.updateEntity(); } @OnLifecycleEvent(ON_PAUSE) public void onPause() { - mMobileNetworkRepository.removeRegister(); + mMobileNetworkRepository.removeRegister(this); } @Override @@ -303,6 +303,4 @@ public abstract class DefaultSubscriptionController extends TelephonyBasePrefere updateEntries(); refreshSummary(mPreference); } - - } diff --git a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java index 971bb498ba9..cf78942972c 100644 --- a/src/com/android/settings/network/telephony/MobileDataPreferenceController.java +++ b/src/com/android/settings/network/telephony/MobileDataPreferenceController.java @@ -58,7 +58,6 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon private SwitchPreference mPreference; private TelephonyManager mTelephonyManager; private SubscriptionManager mSubscriptionManager; - private MobileDataContentObserver mDataContentObserver; private FragmentManager mFragmentManager; @VisibleForTesting int mDialogType; @@ -79,9 +78,7 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon super(context, key); mSubId = subId; mSubscriptionManager = context.getSystemService(SubscriptionManager.class); - mDataContentObserver = new MobileDataContentObserver(new Handler(Looper.getMainLooper())); - mDataContentObserver.setOnMobileDataChangedListener(() -> updateState(mPreference)); - mMobileNetworkRepository = MobileNetworkRepository.createBySubId(context, this, mSubId); + mMobileNetworkRepository = MobileNetworkRepository.getInstance(context); mLifecycleOwner = lifecycleOwner; if (lifecycle != null) { lifecycle.addObserver(this); @@ -103,12 +100,13 @@ public class MobileDataPreferenceController extends TelephonyTogglePreferenceCon @OnLifecycleEvent(ON_START) public void onStart() { - mMobileNetworkRepository.addRegister(mLifecycleOwner); + mMobileNetworkRepository.addRegister(mLifecycleOwner, this, mSubId); + mMobileNetworkRepository.updateEntity(); } @OnLifecycleEvent(ON_STOP) public void onStop() { - mMobileNetworkRepository.removeRegister(); + mMobileNetworkRepository.removeRegister(this); } @Override diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index a9c92186611..0f2d02bfabf 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -158,7 +158,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme MobileNetworkUtils.getSearchableSubscriptionId(context)); Log.d(LOG_TAG, "display subId from getArguments(): " + mSubId); } - mMobileNetworkRepository = MobileNetworkRepository.create(context, this); + mMobileNetworkRepository = MobileNetworkRepository.getInstance(context); mExecutor.execute(() -> { mSubscriptionInfoEntity = mMobileNetworkRepository.getSubInfoById( String.valueOf(mSubId)); @@ -177,6 +177,8 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme new SmsDefaultSubscriptionController(context, KEY_SMS_PREF, getSettingsLifecycle(), this), new MobileDataPreferenceController(context, KEY_MOBILE_DATA_PREF, + getSettingsLifecycle(), this, mSubId), + new ConvertToEsimPreferenceController(context, KEY_CONVERT_TO_ESIM_PREF, getSettingsLifecycle(), this, mSubId)); } @@ -322,7 +324,8 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme @Override public void onResume() { super.onResume(); - mMobileNetworkRepository.addRegister(this); + mMobileNetworkRepository.addRegister(this, this, mSubId); + mMobileNetworkRepository.updateEntity(); // TODO: remove log after fixing b/182326102 Log.d(LOG_TAG, "onResume() subId=" + mSubId); } @@ -350,7 +353,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme @Override public void onDestroy() { super.onDestroy(); - mMobileNetworkRepository.removeRegister(); + mMobileNetworkRepository.removeRegister(this); } @VisibleForTesting @@ -505,7 +508,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme break; } else if (entity.isDefaultSubscriptionSelection) { mSubscriptionInfoEntity = entity; - Log.d(LOG_TAG, "Set subInfo to the default subInfo."); + Log.d(LOG_TAG, "Set subInfo to default subInfo."); } } onSubscriptionDetailChanged(); diff --git a/src/com/android/settings/network/telephony/RoamingPreferenceController.java b/src/com/android/settings/network/telephony/RoamingPreferenceController.java index af56a88a98d..ff5da52525b 100644 --- a/src/com/android/settings/network/telephony/RoamingPreferenceController.java +++ b/src/com/android/settings/network/telephony/RoamingPreferenceController.java @@ -81,7 +81,7 @@ public class RoamingPreferenceController extends TelephonyTogglePreferenceContro super(context, key); mSubId = subId; mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); - mMobileNetworkRepository = MobileNetworkRepository.createBySubId(context, this, mSubId); + mMobileNetworkRepository = MobileNetworkRepository.getInstance(context); mLifecycleOwner = lifecycleOwner; if (lifecycle != null) { lifecycle.addObserver(this); @@ -100,7 +100,8 @@ public class RoamingPreferenceController extends TelephonyTogglePreferenceContro @OnLifecycleEvent(ON_START) public void onStart() { - mMobileNetworkRepository.addRegister(mLifecycleOwner); + mMobileNetworkRepository.addRegister(mLifecycleOwner, this, mSubId); + mMobileNetworkRepository.updateEntity(); if (mListener == null) { mListener = new GlobalSettingsChangeListener(mContext, Settings.Global.DATA_ROAMING) { @@ -126,7 +127,7 @@ public class RoamingPreferenceController extends TelephonyTogglePreferenceContro @OnLifecycleEvent(ON_STOP) public void onStop() { - mMobileNetworkRepository.removeRegister(); + mMobileNetworkRepository.removeRegister(this); stopMonitor(); stopMonitorSubIdSpecific(); } diff --git a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java index b5735efc2f5..912fada3229 100644 --- a/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/MobileNetworkSummaryControllerTest.java @@ -95,10 +95,11 @@ public class MobileNetworkSummaryControllerTest { doReturn(mSubscriptionManager).when(mContext).getSystemService(SubscriptionManager.class); doReturn(mEuiccManager).when(mContext).getSystemService(EuiccManager.class); doReturn(mUserManager).when(mContext).getSystemService(UserManager.class); - mMobileNetworkRepository = MobileNetworkRepository.create(mContext, mMobileNetworkCallback); + mMobileNetworkRepository = MobileNetworkRepository.getInstance(mContext); mLifecycleOwner = () -> mLifecycle; mLifecycle = new Lifecycle(mLifecycleOwner); - mMobileNetworkRepository.addRegister(mLifecycleOwner); + mMobileNetworkRepository.addRegister(mLifecycleOwner, mMobileNetworkCallback, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); when(mTelephonyManager.getNetworkCountryIso()).thenReturn(""); when(mSubscriptionManager.isActiveSubscriptionId(anyInt())).thenReturn(true); @@ -114,7 +115,7 @@ public class MobileNetworkSummaryControllerTest { @After public void tearDown() { - mMobileNetworkRepository.removeRegister(); + mMobileNetworkRepository.removeRegister(mMobileNetworkCallback); SubscriptionUtil.setActiveSubscriptionsForTesting(null); SubscriptionUtil.setAvailableSubscriptionsForTesting(null); } From cb4e0bd018173171a0fd0ec4a3df1db70550084b Mon Sep 17 00:00:00 2001 From: Zoey Chen Date: Mon, 20 Mar 2023 08:51:12 +0000 Subject: [PATCH 12/14] [Settings] Should not show WFC UI in the SIM page if the SIM does not support WFC Bug: 270792637 Test: manual Change-Id: Ic67bd2e766d66c91fc4b0fcf5a5355debd805ac6 --- .../network/telephony/MobileNetworkUtils.java | 8 ++++++-- .../NetworkProviderWifiCallingGroup.java | 20 ++----------------- .../WifiCallingPreferenceController.java | 1 - .../wifi/calling/WifiCallingSettings.java | 3 ++- 4 files changed, 10 insertions(+), 22 deletions(-) diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java index 308da88ed34..265eb167fed 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java +++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java @@ -949,7 +949,12 @@ public class MobileNetworkUtils { boolean isWifiCallingEnabled; if (phoneAccountHandle != null) { final Intent intent = buildPhoneAccountConfigureIntent(context, phoneAccountHandle); - isWifiCallingEnabled = intent != null; + if (intent == null) { + Log.d(TAG, "Can not get phoneAccount configure intent."); + isWifiCallingEnabled = false; + } else { + isWifiCallingEnabled = true; + } } else { if (queryImsState == null) { queryImsState = new WifiCallingQueryImsState(context, subId); @@ -959,7 +964,6 @@ public class MobileNetworkUtils { return isWifiCallingEnabled; } - /** * Returns preferred status of Calls & SMS separately when Provider Model is enabled. */ diff --git a/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java b/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java index 688084f4488..7ad9e03a1a8 100644 --- a/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java +++ b/src/com/android/settings/network/telephony/NetworkProviderWifiCallingGroup.java @@ -314,29 +314,13 @@ public class NetworkProviderWifiCallingGroup extends @VisibleForTesting protected boolean shouldShowWifiCallingForSub(int subId) { if (SubscriptionManager.isValidSubscriptionId(subId) - && MobileNetworkUtils.isWifiCallingEnabled( - mContext, subId, queryImsState(subId), - getPhoneAccountHandleForSubscriptionId(subId)) - && isWifiCallingAvailableForCarrier(subId)) { + && MobileNetworkUtils.isWifiCallingEnabled(mContext, subId, queryImsState(subId), + null)) { return true; } return false; } - private boolean isWifiCallingAvailableForCarrier(int subId) { - boolean isWifiCallingAvailableForCarrier = false; - if (mCarrierConfigManager != null) { - final PersistableBundle carrierConfig = - mCarrierConfigManager.getConfigForSubId(subId); - if (carrierConfig != null) { - isWifiCallingAvailableForCarrier = carrierConfig.getBoolean( - CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL); - } - } - Log.d(TAG, "isWifiCallingAvailableForCarrier:" + isWifiCallingAvailableForCarrier); - return isWifiCallingAvailableForCarrier; - } - @Override public String getPreferenceKey() { return KEY_PREFERENCE_WIFICALLING_GROUP; diff --git a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java index 2d7ba38a801..1bc2f908e3d 100644 --- a/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java +++ b/src/com/android/settings/network/telephony/WifiCallingPreferenceController.java @@ -25,7 +25,6 @@ import android.provider.Settings; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; -import android.telephony.PhoneStateListener; import android.telephony.SubscriptionManager; import android.telephony.TelephonyCallback; import android.telephony.TelephonyManager; diff --git a/src/com/android/settings/wifi/calling/WifiCallingSettings.java b/src/com/android/settings/wifi/calling/WifiCallingSettings.java index 89266964ba7..42ce1b13bab 100644 --- a/src/com/android/settings/wifi/calling/WifiCallingSettings.java +++ b/src/com/android/settings/wifi/calling/WifiCallingSettings.java @@ -257,7 +257,8 @@ public class WifiCallingSettings extends SettingsPreferenceFragment for (SubscriptionInfo subInfo : subInfoList) { int subId = subInfo.getSubscriptionId(); try { - if (queryImsState(subId).isWifiCallingProvisioned()) { + if (MobileNetworkUtils.isWifiCallingEnabled(getContext(), subId, + queryImsState(subId), null)) { selectedList.add(subInfo); } } catch (Exception exception) {} From 90983daa411891840f2ad1d4f89b6a1901b8f0b5 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Fri, 17 Mar 2023 16:26:34 +0800 Subject: [PATCH 13/14] Fix not displaying "Allow restricted settings" "Allow restricted settings" is missed from SPA, added to SPA to fix this issue. Also make the system call in app info more options async to improve performance. Fix: 273678047 Test: Unit test Test: By the following steps, 1. Install an app with accessibility feature from Chrome 2. Go Accessibility page and click on the disabled grey app 3. Go to the app info page, click more options 4. Make sure "Allow restricted settings" is displayed Change-Id: I4adbe2335a32e6a7c4ebe155715684d768e5d1ef --- .../appinfo/AppInfoDashboardFragment.java | 3 +- .../app/appinfo/AppInfoSettingsMoreOptions.kt | 93 +++++++++++++++---- tests/spa_unit/AndroidManifest.xml | 2 + .../appinfo/AppInfoSettingsMoreOptionsTest.kt | 43 +++++++++ 4 files changed, 122 insertions(+), 19 deletions(-) diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index ed45c2be31e..e771ff47761 100644 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -437,7 +437,8 @@ public class AppInfoDashboardFragment extends DashboardFragment } } - private static void showLockScreen(Context context, Runnable successRunnable) { + /** Shows the lock screen if the keyguard is secured. */ + public static void showLockScreen(Context context, Runnable successRunnable) { final KeyguardManager keyguardManager = context.getSystemService( KeyguardManager.class); diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettingsMoreOptions.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettingsMoreOptions.kt index fbdde0b982c..7f7d8c544b4 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettingsMoreOptions.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettingsMoreOptions.kt @@ -16,17 +16,25 @@ package com.android.settings.spa.app.appinfo +import android.app.AppOpsManager import android.content.Context import android.content.pm.ApplicationInfo import android.os.UserManager +import android.widget.Toast import androidx.compose.runtime.Composable import androidx.compose.runtime.State +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.produceState +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import com.android.settings.R import com.android.settings.Utils +import com.android.settings.applications.appinfo.AppInfoDashboardFragment import com.android.settingslib.spa.widget.scaffold.MoreOptionsAction +import com.android.settingslib.spaprivileged.framework.common.appOpsManager import com.android.settingslib.spaprivileged.framework.common.devicePolicyManager import com.android.settingslib.spaprivileged.framework.common.userManager import com.android.settingslib.spaprivileged.model.app.IPackageManagers @@ -35,6 +43,8 @@ import com.android.settingslib.spaprivileged.model.app.userId import com.android.settingslib.spaprivileged.model.enterprise.Restrictions import com.android.settingslib.spaprivileged.template.scaffold.RestrictedMenuItem import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.withContext @Composable @@ -44,13 +54,11 @@ fun AppInfoSettingsMoreOptions( packageManagers: IPackageManagers = PackageManagers, ) { val state = app.produceState(packageManagers).value ?: return - when { - // We don't allow uninstalling update for DO/PO if it's a system app, because it will clear - // data on all users. We also don't allow uninstalling for all users if it's DO/PO for any - // user. - state.isProfileOrDeviceOwner -> return - !state.shownUninstallUpdates && !state.shownUninstallForAllUsers -> return - } + var restrictedSettingsAllowed by rememberSaveable { mutableStateOf(false) } + if (!state.shownUninstallUpdates && + !state.shownUninstallForAllUsers && + !(state.shouldShowAccessRestrictedSettings && !restrictedSettingsAllowed) + ) return MoreOptionsAction { val restrictions = Restrictions(userId = app.userId, keys = listOf(UserManager.DISALLOW_APPS_CONTROL)) @@ -70,13 +78,37 @@ fun AppInfoSettingsMoreOptions( packageInfoPresenter.startUninstallActivity(forAllUsers = true) } } + if (state.shouldShowAccessRestrictedSettings && !restrictedSettingsAllowed) { + MenuItem(text = stringResource(R.string.app_restricted_settings_lockscreen_title)) { + app.allowRestrictedSettings(packageInfoPresenter.context) { + restrictedSettingsAllowed = true + } + } + } + } +} + +private fun ApplicationInfo.allowRestrictedSettings(context: Context, onSuccess: () -> Unit) { + AppInfoDashboardFragment.showLockScreen(context) { + context.appOpsManager.setMode( + AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS, + uid, + packageName, + AppOpsManager.MODE_ALLOWED, + ) + onSuccess() + val toastString = context.getString( + R.string.toast_allows_restricted_settings_successfully, + loadLabel(context.packageManager), + ) + Toast.makeText(context, toastString, Toast.LENGTH_LONG).show() } } private data class AppInfoSettingsMoreOptionsState( - val isProfileOrDeviceOwner: Boolean, val shownUninstallUpdates: Boolean, val shownUninstallForAllUsers: Boolean, + val shouldShowAccessRestrictedSettings: Boolean, ) @Composable @@ -86,20 +118,40 @@ private fun ApplicationInfo.produceState( val context = LocalContext.current return produceState(initialValue = null, this) { withContext(Dispatchers.IO) { - value = AppInfoSettingsMoreOptionsState( - isProfileOrDeviceOwner = Utils.isProfileOrDeviceOwner( - context.userManager, context.devicePolicyManager, packageName - ), - shownUninstallUpdates = isShowUninstallUpdates(context), - shownUninstallForAllUsers = isShowUninstallForAllUsers( - userManager = context.userManager, - packageManagers = packageManagers, - ), - ) + value = getMoreOptionsState(context, packageManagers) } } } +private suspend fun ApplicationInfo.getMoreOptionsState( + context: Context, + packageManagers: IPackageManagers, +) = coroutineScope { + val shownUninstallUpdatesDeferred = async { + isShowUninstallUpdates(context) + } + val shownUninstallForAllUsersDeferred = async { + isShowUninstallForAllUsers( + userManager = context.userManager, + packageManagers = packageManagers, + ) + } + val shouldShowAccessRestrictedSettingsDeferred = async { + shouldShowAccessRestrictedSettings(context.appOpsManager) + } + val isProfileOrDeviceOwner = + Utils.isProfileOrDeviceOwner(context.userManager, context.devicePolicyManager, packageName) + AppInfoSettingsMoreOptionsState( + // We don't allow uninstalling update for DO/PO if it's a system app, because it will clear + // data on all users. + shownUninstallUpdates = !isProfileOrDeviceOwner && shownUninstallUpdatesDeferred.await(), + // We also don't allow uninstalling for all users if it's DO/PO for any user. + shownUninstallForAllUsers = + !isProfileOrDeviceOwner && shownUninstallForAllUsersDeferred.await(), + shouldShowAccessRestrictedSettings = shouldShowAccessRestrictedSettingsDeferred.await(), + ) +} + private fun ApplicationInfo.isShowUninstallUpdates(context: Context): Boolean = isUpdatedSystemApp && context.userManager.isUserAdmin(userId) && !context.resources.getBoolean(R.bool.config_disable_uninstall_update) @@ -116,3 +168,8 @@ private fun ApplicationInfo.isOtherUserHasInstallPackage( ): Boolean = userManager.aliveUsers .filter { it.id != userId } .any { packageManagers.isPackageInstalledAsUser(packageName, it.id) } + +private fun ApplicationInfo.shouldShowAccessRestrictedSettings(appOpsManager: AppOpsManager) = + appOpsManager.noteOpNoThrow( + AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS, uid, packageName, null, null + ) == AppOpsManager.MODE_IGNORED diff --git a/tests/spa_unit/AndroidManifest.xml b/tests/spa_unit/AndroidManifest.xml index ec777410080..5a7f5659ce6 100644 --- a/tests/spa_unit/AndroidManifest.xml +++ b/tests/spa_unit/AndroidManifest.xml @@ -19,6 +19,8 @@ xmlns:tools="http://schemas.android.com/tools" package="com.android.settings.tests.spa_unit"> + + diff --git a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppInfoSettingsMoreOptionsTest.kt b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppInfoSettingsMoreOptionsTest.kt index 318debab238..71035163057 100644 --- a/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppInfoSettingsMoreOptionsTest.kt +++ b/tests/spa_unit/src/com/android/settings/spa/app/appinfo/AppInfoSettingsMoreOptionsTest.kt @@ -16,6 +16,8 @@ package com.android.settings.spa.app.appinfo +import android.app.AppOpsManager +import android.app.KeyguardManager import android.app.admin.DevicePolicyManager import android.content.Context import android.content.pm.ApplicationInfo @@ -27,6 +29,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.test.assertIsNotDisplayed import androidx.compose.ui.test.hasText import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.onRoot import androidx.compose.ui.test.performClick import androidx.test.core.app.ApplicationProvider @@ -36,6 +39,7 @@ import com.android.settings.R import com.android.settings.Utils import com.android.settingslib.spa.testutils.delay import com.android.settingslib.spa.testutils.waitUntilExists +import com.android.settingslib.spaprivileged.framework.common.appOpsManager import com.android.settingslib.spaprivileged.framework.common.devicePolicyManager import com.android.settingslib.spaprivileged.framework.common.userManager import com.android.settingslib.spaprivileged.model.app.IPackageManagers @@ -46,6 +50,7 @@ import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.verify import org.mockito.MockitoSession import org.mockito.Spy import org.mockito.quality.Strictness @@ -73,6 +78,12 @@ class AppInfoSettingsMoreOptionsTest { @Mock private lateinit var devicePolicyManager: DevicePolicyManager + @Mock + private lateinit var appOpsManager: AppOpsManager + + @Mock + private lateinit var keyguardManager: KeyguardManager + @Spy private var resources = context.resources @@ -90,6 +101,9 @@ class AppInfoSettingsMoreOptionsTest { whenever(context.packageManager).thenReturn(packageManager) whenever(context.userManager).thenReturn(userManager) whenever(context.devicePolicyManager).thenReturn(devicePolicyManager) + whenever(context.appOpsManager).thenReturn(appOpsManager) + whenever(context.getSystemService(KeyguardManager::class.java)).thenReturn(keyguardManager) + whenever(keyguardManager.isKeyguardSecure).thenReturn(false) whenever(Utils.isProfileOrDeviceOwner(userManager, devicePolicyManager, PACKAGE_NAME)) .thenReturn(false) } @@ -143,6 +157,35 @@ class AppInfoSettingsMoreOptionsTest { ) } + @Test + fun shouldShowAccessRestrictedSettings() { + whenever( + appOpsManager.noteOpNoThrow( + AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS, UID, PACKAGE_NAME, null, null + ) + ).thenReturn(AppOpsManager.MODE_IGNORED) + val app = ApplicationInfo().apply { + packageName = PACKAGE_NAME + uid = UID + } + + setContent(app) + composeTestRule.onRoot().performClick() + + composeTestRule.waitUntilExists( + hasText(context.getString(R.string.app_restricted_settings_lockscreen_title)) + ) + composeTestRule + .onNodeWithText(context.getString(R.string.app_restricted_settings_lockscreen_title)) + .performClick() + verify(appOpsManager).setMode( + AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS, + UID, + PACKAGE_NAME, + AppOpsManager.MODE_ALLOWED, + ) + } + private fun setContent(app: ApplicationInfo) { composeTestRule.setContent { CompositionLocalProvider(LocalContext provides context) { From 5164149efc0b20fe6e3a35809dea4387636d429b Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Thu, 16 Mar 2023 17:29:55 -0400 Subject: [PATCH 14/14] Add missing conversation field NotificationChannel#EDIT_CONVERSATION should show both 'demote conversation' and 'promote conversation' fields. Test: View Partial and Full Settings for promoted and demoted channels Fixes: 273508155 Change-Id: I4a17a73d695d7c79837fc647b79968f535fa4393 --- res/xml/conversation_notification_settings.xml | 7 +++++++ .../notification/app/ConversationNotificationSettings.java | 1 + 2 files changed, 8 insertions(+) diff --git a/res/xml/conversation_notification_settings.xml b/res/xml/conversation_notification_settings.xml index 9078e2d0905..89812a774ae 100644 --- a/res/xml/conversation_notification_settings.xml +++ b/res/xml/conversation_notification_settings.xml @@ -96,4 +96,11 @@ android:summary="@string/demote_conversation_summary" settings:allowDividerAbove="true"/> + + + diff --git a/src/com/android/settings/notification/app/ConversationNotificationSettings.java b/src/com/android/settings/notification/app/ConversationNotificationSettings.java index b452309f84c..02ea6c060ec 100644 --- a/src/com/android/settings/notification/app/ConversationNotificationSettings.java +++ b/src/com/android/settings/notification/app/ConversationNotificationSettings.java @@ -99,6 +99,7 @@ public class ConversationNotificationSettings extends NotificationSettings { mControllers.add(new BubblePreferenceController(context, getChildFragmentManager(), mBackend, false /* isAppPage */, null /* dependentFieldListener */)); mControllers.add(new ConversationDemotePreferenceController(context, this, mBackend)); + mControllers.add(new ConversationPromotePreferenceController(context, this, mBackend)); mControllers.add(new BubbleCategoryPreferenceController(context)); mControllers.add(new BubbleLinkPreferenceController(context)); return new ArrayList<>(mControllers);