Merge "Add FLAG_RECEIVER_FOREGROUND to run redirect intent at foreground priority" into rvc-qpr-dev
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 19514cc..90e02be 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -3254,7 +3254,7 @@
<string name="restriction_settings_title" msgid="4293731103465972557">"القيود"</string>
<string name="restriction_menu_reset" msgid="92859464456364092">"إزالة القيود"</string>
<string name="restriction_menu_change_pin" msgid="2505923323199003718">"تغيير رمز PIN"</string>
- <string name="help_label" msgid="2896538416436125883">"المساعدة والتعليقات"</string>
+ <string name="help_label" msgid="2896538416436125883">"المساعدة والملاحظات والآراء"</string>
<string name="support_summary" msgid="1034146931237148885">"مقالات المساعدة والاتصال الهاتفي والمحادثة والبدء"</string>
<string name="user_account_title" msgid="6389636876210834864">"حساب المحتوى"</string>
<string name="user_picture_title" msgid="7176437495107563321">"معرف الصورة"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 8b0d86d..e762b45 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -1371,7 +1371,7 @@
<string name="storage_settings_summary" product="default" msgid="267557695753980969">"Oslobađanje SD kartice, prikaz dostupnog skladišta"</string>
<string name="imei_multi_sim" msgid="71477088017585479">"IMEI (otvor za SIM: %1$d)"</string>
<string name="view_saved_network" msgid="1232387673095080910">"Da biste videli, odaberite sačuvanu mrežu"</string>
- <string name="status_number" product="tablet" msgid="3597945414666253183">"Broj mobilnog direktorijuma"</string>
+ <string name="status_number" product="tablet" msgid="3597945414666253183">"Broj mobilnog foldera"</string>
<string name="status_number" product="default" msgid="8407999629121682207">"Broj telefona"</string>
<string name="status_number_sim_slot" product="tablet" msgid="6582203988975619529">"MDN (otvor za SIM: %1$d)"</string>
<string name="status_number_sim_slot" product="default" msgid="5724823197745786398">"Br. tel. (otvor za SIM: %1$d)"</string>
@@ -3503,7 +3503,7 @@
<string name="work_sync_dialog_yes" msgid="9161415252411868574">"Zameni"</string>
<string name="work_sync_dialog_message" msgid="1328692374812258546">"Zvukovi sa ličnog profila će se koristiti za poslovni profil"</string>
<string name="ringtones_install_custom_sound_title" msgid="3885712267015760638">"Dodati prilagođeni zvuk?"</string>
- <string name="ringtones_install_custom_sound_content" msgid="5844996763705884979">"Ova datoteka će biti kopirana u direktorijum <xliff:g id="FOLDER_NAME">%s</xliff:g>"</string>
+ <string name="ringtones_install_custom_sound_content" msgid="5844996763705884979">"Ova datoteka će biti kopirana u folder <xliff:g id="FOLDER_NAME">%s</xliff:g>"</string>
<string name="ringtones_category_preference_title" msgid="26680768777533727">"Melodije zvona"</string>
<string name="other_sound_category_preference_title" msgid="8182757473602586634">"Drugi zvukovi i vibracije"</string>
<string name="configure_notification_settings" msgid="1492820231694314376">"Obaveštenja"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 6c78162..5bbba57 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -2601,9 +2601,9 @@
<string name="battery_saver_schedule_settings_title" msgid="3688019979950082237">"Angiv en tidsplan"</string>
<string name="battery_saver_turn_on_summary" msgid="1433919417587171160">"Forlæng batteritiden"</string>
<string name="battery_saver_sticky_title_new" msgid="5942813274115684599">"Deaktiver, når enheden er opladet"</string>
- <string name="battery_saver_sticky_description_new" product="default" msgid="6862168106613838677">"Batterisparefunktion slås fra, når din telefon er på <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
- <string name="battery_saver_sticky_description_new" product="tablet" msgid="6740553373344759992">"Batterisparefunktion slås fra, når din tablet er på <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
- <string name="battery_saver_sticky_description_new" product="device" msgid="8512106347424406909">"Batterisparefunktion slås fra, når din enhed er på <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+ <string name="battery_saver_sticky_description_new" product="default" msgid="6862168106613838677">"Batterisparefunktionen slås fra, når din telefon er på <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+ <string name="battery_saver_sticky_description_new" product="tablet" msgid="6740553373344759992">"Batterisparefunktionen slås fra, når din tablet er på <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+ <string name="battery_saver_sticky_description_new" product="device" msgid="8512106347424406909">"Batterisparefunktionen slås fra, når din enhed er på <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
<!-- no translation found for battery_saver_seekbar_title (3712266470054006641) -->
<skip />
<string name="battery_saver_seekbar_title_placeholder" msgid="7141264642540687540">"Aktivér"</string>
@@ -3385,7 +3385,7 @@
<string name="zen_mode_block_effect_light" msgid="1997222991427784993">"Undlad at bruge blinkende lys"</string>
<string name="zen_mode_block_effect_peek" msgid="2525844009475266022">"Undlad at vise notifikationer på skærmen"</string>
<string name="zen_mode_block_effect_status" msgid="5765965061064691918">"Skjul statusbjælkeikoner øverst på skærmen"</string>
- <string name="zen_mode_block_effect_badge" msgid="332151258515152429">"Skjul notifikationscirkler på appikoner"</string>
+ <string name="zen_mode_block_effect_badge" msgid="332151258515152429">"Skjul notifikationsprikker på appikoner"</string>
<string name="zen_mode_block_effect_ambient" msgid="1247740599476031543">"Væk ikke ved notifikationer"</string>
<string name="zen_mode_block_effect_list" msgid="7549367848660137118">"Skjul i panelet, der trækkes ned"</string>
<string name="zen_mode_block_effect_summary_none" msgid="6688519142395714659">"Aldrig"</string>
@@ -3483,7 +3483,7 @@
<string name="snooze_options_title" msgid="2109795569568344617">"Tillad udsættelse af notifikationer"</string>
<string name="hide_silent_icons_title" msgid="5951392023601167577">"Skjul ikoner fra diskrete notifikationer"</string>
<string name="hide_silent_icons_summary" msgid="623763437631637232">"Ikoner fra diskrete notifikationer vises ikke på statusbjælken"</string>
- <string name="notification_badging_title" msgid="5469616894819568917">"Notifikationscirkel på appikon"</string>
+ <string name="notification_badging_title" msgid="5469616894819568917">"Notifikationsprik på appikon"</string>
<string name="notification_people_strip_title" msgid="1185857822541001139">"Vis linje med seneste samtaler"</string>
<string name="notification_bubbles_title" msgid="5681506665322329301">"Bobler"</string>
<string name="bubbles_feature_education" msgid="4088275802688887634">"Nogle notifikationer og andet indhold kan blive vist som bobler på skærmen. Tryk på en boble for at åbne den. Træk den ned ad skærmen for at lukke den."</string>
@@ -3693,8 +3693,8 @@
<string name="app_notification_block_summary" msgid="1804611676339341551">"Vis aldrig disse notifikationer"</string>
<string name="notification_content_block_title" msgid="6689085826061361351">"Vis notifikationer"</string>
<string name="notification_content_block_summary" msgid="329171999992248925">"Vis aldrig notifikationer i underretningspanelet eller på eksterne enheder"</string>
- <string name="notification_badge_title" msgid="6854537463548411313">"Tillad notifikationscirkel"</string>
- <string name="notification_channel_badge_title" msgid="6505542437385640049">"Vis notifikationscirkel"</string>
+ <string name="notification_badge_title" msgid="6854537463548411313">"Tillad notifikationsprik"</string>
+ <string name="notification_channel_badge_title" msgid="6505542437385640049">"Vis notifikationsprik"</string>
<string name="app_notification_override_dnd_title" msgid="3769539356442226691">"Tilsidesæt Forstyr ikke"</string>
<string name="app_notification_override_dnd_summary" msgid="4894641191397562920">"Bliv ved med at få disse notifikationer, når Forstyr ikke er aktiveret"</string>
<string name="app_notification_visibility_override_title" msgid="7778628150022065920">"Låseskærm"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 2f8e7ec..6bc4d35 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -2598,7 +2598,7 @@
<string name="battery_saver_auto_percentage" msgid="558533724806281980">"Bateria-mailaren ehunekoan oinarrituta"</string>
<string name="battery_saver_auto_routine_summary" msgid="3913145448299472628">"Bateria kargatzeko ohiko ordua iritsi aurretik bateria agortzeko arriskua badago aktibatzen da bateria-aurrezlea"</string>
<string name="battery_saver_auto_percentage_summary" msgid="6190884450723824287">"Bateria-maila <xliff:g id="PERCENT">%1$s</xliff:g> denean aktibatuko da"</string>
- <string name="battery_saver_schedule_settings_title" msgid="3688019979950082237">"Ezarri programazioa"</string>
+ <string name="battery_saver_schedule_settings_title" msgid="3688019979950082237">"Ezarri programazio bat"</string>
<string name="battery_saver_turn_on_summary" msgid="1433919417587171160">"Luzatu bateriaren iraupena"</string>
<string name="battery_saver_sticky_title_new" msgid="5942813274115684599">"Desaktibatu kargatuta dagoenean"</string>
<string name="battery_saver_sticky_description_new" product="default" msgid="6862168106613838677">"Telefonoaren bateria <xliff:g id="PERCENT">%1$s</xliff:g> denean, desaktibatu egiten da bateria-aurrezlea"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index fa12f10..1a599f2 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -2600,7 +2600,7 @@
<string name="battery_saver_auto_percentage_summary" msgid="6190884450723824287">"<xliff:g id="PERCENT">%1$s</xliff:g>-os értéknél kapcsol be"</string>
<string name="battery_saver_schedule_settings_title" msgid="3688019979950082237">"Ütemezés beállítása"</string>
<string name="battery_saver_turn_on_summary" msgid="1433919417587171160">"Az akkumulátor élettartamának növelése"</string>
- <string name="battery_saver_sticky_title_new" msgid="5942813274115684599">"Kikapcsolás töltés közben"</string>
+ <string name="battery_saver_sticky_title_new" msgid="5942813274115684599">"Kikapcsolás feltöltés után"</string>
<string name="battery_saver_sticky_description_new" product="default" msgid="6862168106613838677">"Az Akkumulátorkímélő mód <xliff:g id="PERCENT">%1$s</xliff:g>-os töltöttségi szint elérésekor kikapcsol"</string>
<string name="battery_saver_sticky_description_new" product="tablet" msgid="6740553373344759992">"Az Akkumulátorkímélő mód <xliff:g id="PERCENT">%1$s</xliff:g>-os töltöttségi szint elérésekor kikapcsol"</string>
<string name="battery_saver_sticky_description_new" product="device" msgid="8512106347424406909">"Az Akkumulátorkímélő mód <xliff:g id="PERCENT">%1$s</xliff:g>-os töltöttségi szint elérésekor kikapcsol"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index e60985c..d038e65 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -1371,7 +1371,7 @@
<string name="storage_settings_summary" product="default" msgid="267557695753980969">"Ослобађање SD картице, приказ доступног складишта"</string>
<string name="imei_multi_sim" msgid="71477088017585479">"IMEI (отвор за SIM: %1$d)"</string>
<string name="view_saved_network" msgid="1232387673095080910">"Да бисте видели, одаберите сачувану мрежу"</string>
- <string name="status_number" product="tablet" msgid="3597945414666253183">"Број мобилног директоријума"</string>
+ <string name="status_number" product="tablet" msgid="3597945414666253183">"Број мобилног фолдера"</string>
<string name="status_number" product="default" msgid="8407999629121682207">"Број телефона"</string>
<string name="status_number_sim_slot" product="tablet" msgid="6582203988975619529">"MDN (отвор за SIM: %1$d)"</string>
<string name="status_number_sim_slot" product="default" msgid="5724823197745786398">"Бр. тел. (отвор за SIM: %1$d)"</string>
@@ -3503,7 +3503,7 @@
<string name="work_sync_dialog_yes" msgid="9161415252411868574">"Замени"</string>
<string name="work_sync_dialog_message" msgid="1328692374812258546">"Звукови са личног профила ће се користити за пословни профил"</string>
<string name="ringtones_install_custom_sound_title" msgid="3885712267015760638">"Додати прилагођени звук?"</string>
- <string name="ringtones_install_custom_sound_content" msgid="5844996763705884979">"Ова датотека ће бити копирана у директоријум <xliff:g id="FOLDER_NAME">%s</xliff:g>"</string>
+ <string name="ringtones_install_custom_sound_content" msgid="5844996763705884979">"Ова датотека ће бити копирана у фолдер <xliff:g id="FOLDER_NAME">%s</xliff:g>"</string>
<string name="ringtones_category_preference_title" msgid="26680768777533727">"Мелодије звона"</string>
<string name="other_sound_category_preference_title" msgid="8182757473602586634">"Други звукови и вибрације"</string>
<string name="configure_notification_settings" msgid="1492820231694314376">"Обавештења"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index fe16148..65e1c93 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -2483,9 +2483,9 @@
<string name="battery_tip_smart_battery_title" product="tablet" msgid="6813017377960004819">"Подовжте час роботи акумулятора планшета"</string>
<string name="battery_tip_smart_battery_title" product="device" msgid="4805599360437606335">"Подовжте час роботи акумулятора пристрою"</string>
<string name="battery_tip_smart_battery_summary" msgid="3592965553502362965">"Увімкніть диспетчер заряду акумулятора"</string>
- <string name="battery_tip_early_heads_up_title" msgid="4411387863476629452">"Увімкніть режим економії заряду акумулятора"</string>
+ <string name="battery_tip_early_heads_up_title" msgid="4411387863476629452">"Увімкніть режим енергозбереження"</string>
<string name="battery_tip_early_heads_up_summary" msgid="578523794827443977">"Акумулятор може розрядитися швидше, ніж зазвичай"</string>
- <string name="battery_tip_early_heads_up_done_title" msgid="4413270905575486715">"Режим економії заряду акумулятора ввімкнено"</string>
+ <string name="battery_tip_early_heads_up_done_title" msgid="4413270905575486715">"Режим енергозбереження ввімкнено"</string>
<string name="battery_tip_early_heads_up_done_summary" msgid="7858923105760361208">"Деякі функції можуть не працювати"</string>
<string name="battery_tip_high_usage_title" product="default" msgid="2375953293196088319">"Телефон використовується більше, ніж зазвичай"</string>
<string name="battery_tip_high_usage_title" product="tablet" msgid="8515903411746145740">"Планшет використовується більше, ніж зазвичай"</string>
@@ -2636,7 +2636,7 @@
<string name="battery_sugg_bluetooth_headset" msgid="6495519793211758353">"Спробуйте з’єднатися з іншим пристроєм Bluetooth"</string>
<string name="battery_desc_apps" msgid="4187483940383266017">"Як програма використовує акумулятор"</string>
<string name="battery_sugg_apps_info" msgid="4796917242296658454">"Зупиніть або видаліть цю програму"</string>
- <string name="battery_sugg_apps_gps" msgid="7221335088647925110">"Виберіть режим економії заряду акумулятора"</string>
+ <string name="battery_sugg_apps_gps" msgid="7221335088647925110">"Виберіть режим енергозбереження"</string>
<string name="battery_sugg_apps_settings" msgid="6527223370162382166">"У програмі можуть бути налаштування режиму енергозбереження"</string>
<string name="battery_desc_users" msgid="1959428568888686847">"Використання акумулятора користувачем"</string>
<string name="battery_desc_unaccounted" msgid="1649497860893660763">"Невраховане споживання заряду акумулятора"</string>
@@ -2667,7 +2667,7 @@
<string name="menu_stats_refresh" msgid="6727628139586938835">"Оновити"</string>
<string name="process_mediaserver_label" msgid="6135260215912215092">"Медіа-сервер"</string>
<string name="process_dex2oat_label" msgid="1190208677726583153">"Оптимізація додатка"</string>
- <string name="battery_saver" msgid="7737147344510595864">"Режим економії заряду акумулятора"</string>
+ <string name="battery_saver" msgid="7737147344510595864">"Режим енергозбереження"</string>
<string name="battery_saver_auto_title" msgid="6789753787070176144">"Вмикати автоматично"</string>
<string name="battery_saver_auto_no_schedule" msgid="5123639867350138893">"Немає розкладу"</string>
<string name="battery_saver_auto_routine" msgid="4656495097900848608">"На основі звичного часу заряджання"</string>
@@ -2677,13 +2677,13 @@
<string name="battery_saver_schedule_settings_title" msgid="3688019979950082237">"Налаштувати розклад"</string>
<string name="battery_saver_turn_on_summary" msgid="1433919417587171160">"Подовжте час роботи акумулятора"</string>
<string name="battery_saver_sticky_title_new" msgid="5942813274115684599">"Вимикати, коли заряджено"</string>
- <string name="battery_saver_sticky_description_new" product="default" msgid="6862168106613838677">"Режим економії заряду акумулятора вимкнеться, коли рівень заряду телефона досягне <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
+ <string name="battery_saver_sticky_description_new" product="default" msgid="6862168106613838677">"Режим енергозбереження вимкнеться, коли рівень заряду телефона досягне <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
<string name="battery_saver_sticky_description_new" product="tablet" msgid="6740553373344759992">"Режим енергозбереження буде вимкнено, коли рівень заряду планшета досягне <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
<string name="battery_saver_sticky_description_new" product="device" msgid="8512106347424406909">"Режим енергозбереження буде вимкнено, коли рівень заряду пристрою досягне <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
<!-- no translation found for battery_saver_seekbar_title (3712266470054006641) -->
<skip />
<string name="battery_saver_seekbar_title_placeholder" msgid="7141264642540687540">"Увімкнути"</string>
- <string name="battery_saver_master_switch_title" msgid="3474312070095834915">"Використовувати режим економії заряду акумулятора"</string>
+ <string name="battery_saver_master_switch_title" msgid="3474312070095834915">"Використовувати режим енергозбереження"</string>
<string name="battery_saver_turn_on_automatically_title" msgid="7857393318205740864">"Вмикати автоматично"</string>
<string name="battery_saver_turn_on_automatically_never" msgid="6194649389871448663">"Ніколи"</string>
<string name="battery_saver_turn_on_automatically_pct" msgid="4294335680892392449">"коли рівень заряду акумулятора – <xliff:g id="PERCENT">%1$s</xliff:g>"</string>
diff --git a/res/values-uz/arrays.xml b/res/values-uz/arrays.xml
index 7b0af94..4788b5c 100644
--- a/res/values-uz/arrays.xml
+++ b/res/values-uz/arrays.xml
@@ -73,7 +73,7 @@
<item msgid="7388036070768806193">"Qidiruv…"</item>
<item msgid="1656176059757237036">"Ulanmoqda…"</item>
<item msgid="3249903732481917388">"Tasdiqdan o‘tilmoqda…"</item>
- <item msgid="7789156794775399931">"IP manzil o‘zlashtirilmoqda…"</item>
+ <item msgid="7789156794775399931">"IP manzil olinmoqda…"</item>
<item msgid="492518447401534767">"Ulangan"</item>
<item msgid="4322989558568666518">"Muzlatildi"</item>
<item msgid="286164147080824297">"Uzilmoqda…"</item>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 3c2bbbd..37f7b52 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -98,7 +98,7 @@
<string name="bluetooth_show_received_files" msgid="685424727760622632">"Qabul qilingan fayllar"</string>
<string name="bluetooth_show_files_received_via_bluetooth" msgid="7097860463458492953">"Bluetooth orqali olingan fayllar"</string>
<string name="bluetooth_devices_card_off_title" msgid="1320149821945129127">"Bluetooth yoqilmagan"</string>
- <string name="bluetooth_devices_card_off_summary" msgid="2276527382891105858">"Yoqish uchun ustiga bosing"</string>
+ <string name="bluetooth_devices_card_off_summary" msgid="2276527382891105858">"Yoqish uchun bosing"</string>
<string name="device_picker" msgid="2427027896389445414">"Bluetooth qurilmani tanlang"</string>
<string name="bluetooth_ask_enablement" msgid="1529030199895339199">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi Bluetooth xizmatini yoqmoqchi"</string>
<string name="bluetooth_ask_disablement" msgid="1879788777942714761">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi Bluetooth xizmatini o‘chirib qo‘ymoqchi"</string>
@@ -296,7 +296,7 @@
<string name="show_profile_info_on_lockscreen_label" msgid="5734739022887933365">"Profil ma‘lumotini qulflangan ekranda ko‘rsatish"</string>
<string name="Accounts_settings_title" msgid="8434263183710375412">"Hisoblar"</string>
<string name="location_settings_title" msgid="8375074508036087178">"Joylashuv"</string>
- <string name="location_settings_master_switch_title" msgid="4232810467362584112">"Joylashuv axborotidan foydalanish"</string>
+ <string name="location_settings_master_switch_title" msgid="4232810467362584112">"Joylashuvni aniqlash"</string>
<string name="location_settings_summary_location_off" msgid="4797932754681162262">"Yoqilmagan"</string>
<plurals name="location_settings_summary_location_on" formatted="false" msgid="1019959038518185676">
<item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta ilovada joylashuvga ruxsat bor</item>
@@ -4464,9 +4464,9 @@
<string name="swipe_up_to_switch_apps_suggestion_title" msgid="5754081720589900007">"Yangi asosiy tugmani sinang"</string>
<string name="swipe_up_to_switch_apps_suggestion_summary" msgid="8885866570559435110">"Ilovalarni almashtirish uchun yangi ishorani yoqing"</string>
<string name="edge_to_edge_navigation_title" msgid="714427081306043819">"Ishorali navigatsiya"</string>
- <string name="edge_to_edge_navigation_summary" msgid="8497033810637690561">"Bosh ekranga qaytish uchun ekranning pastidan tepaga qarab suring. Bir ilovadan boshqasiga oʻtish uchun pastdan tepaga surib, bosib turing va qoʻyib yuboring. Orqaga qaytish uchun chap yoki oʻng burchakdan teskari tomonga suring."</string>
+ <string name="edge_to_edge_navigation_summary" msgid="8497033810637690561">"Bosh ekranga qaytish uchun ekranning pastidan tepaga qarab suring. Bir ilovadan boshqasiga almashish uchun pastdan tepaga surib, biroz ushlab turing va qoʻyib yuboring. Orqaga qaytish uchun ekranning chap yoki oʻng chetidan markazga qarab suring."</string>
<string name="legacy_navigation_title" msgid="7877402855994423727">"3 tugmali navigatsiya"</string>
- <string name="legacy_navigation_summary" msgid="5905301067778326433">"Orqaga, Boshiga va bir ilovadan boshqasiga oʻtish tugmalari ekranning pastida joylashgan."</string>
+ <string name="legacy_navigation_summary" msgid="5905301067778326433">"Orqaga qaytish, bosh ekranga chiqish va ilovalar orasida almashish uchun ekran pastida chiqadigan tugmalardan foydalaning."</string>
<string name="keywords_system_navigation" msgid="3131782378486554934">"tizim navigatsiyasi, 2 tugmali navigatsiya, 3 tugmali navigatsiya, ishorali navigatsiya"</string>
<string name="gesture_not_supported_dialog_message" msgid="5316512246119347889">"Bu funksiya bosh ekran ilovasida (<xliff:g id="DEFAULT_HOME_APP">%s</xliff:g>) ishlamaydi"</string>
<string name="gesture_not_supported_positive_button" msgid="7909969459977021893">"Bosh ekran ilovasini almashtirish"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 103f264..c1c6a92 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -5654,9 +5654,9 @@
<!-- Summary for the battery high usage tip, which presents battery may run out earlier [CHAR LIMIT=NONE] -->
<string name="battery_tip_high_usage_summary">Battery may run out earlier than usual</string>
<!-- Title for the battery limited temporarily tip [CHAR LIMIT=NONE] -->
- <string name="battery_tip_limited_temporarily_title">Battery limited temporarily</string>
+ <string name="battery_tip_limited_temporarily_title">Preserving battery health</string>
<!-- Summary for the battery limited temporarily tip [CHAR LIMIT=NONE] -->
- <string name="battery_tip_limited_temporarily_summary">Helps preserve battery health. Tap to learn more.</string>
+ <string name="battery_tip_limited_temporarily_summary">Battery limited temporarily. Tap to learn more.</string>
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
<string name="battery_tip_dialog_message" product="default">Your phone has been used more than usual. Your battery may run out sooner than expected.\n\nTop apps by battery usage:</string>
<!-- Message for battery tip dialog to show the status about the battery [CHAR LIMIT=NONE] -->
@@ -7193,6 +7193,8 @@
<string name="help_url_sound" translatable="false"></string>
<!-- Help URL, Battery [DO NOT TRANSLATE] -->
<string name="help_url_battery" translatable="false"></string>
+ <!-- Help URL, Battery Defender [DO NOT TRANSLATE] -->
+ <string name="help_url_battery_defender" translatable="false"></string>
<!-- Help URL, Accounts [DO NOT TRANSLATE] -->
<string name="help_url_accounts" translatable="false"></string>
<!-- Help URL, Choose lockscreen [DO NOT TRANSLATE] -->
@@ -11480,7 +11482,7 @@
<string name="pref_title_network_details">Network details</string>
<!-- Warning text about the visibility of device name. [CHAR LIMIT=NONE] -->
- <string name="about_phone_device_name_warning">Your device name is visible to apps on your phone. It may also be seen by other people when you connect to Bluetooth devices or set up a Wi-Fi hotspot.</string>
+ <string name="about_phone_device_name_warning">Your device name is visible to apps on your phone. It may also be seen by other people when you connect to Bluetooth devices, connect to a Wi-Fi network or set up a Wi-Fi hotspot.</string>
<!-- Title for Connected device shortcut [CHAR LIMIT=30] -->
<string name="devices_title">Devices</string>
diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java
index 4dd9a40..be383dc 100644
--- a/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java
+++ b/src/com/android/settings/bluetooth/BluetoothPermissionActivity.java
@@ -34,6 +34,8 @@
import com.android.internal.app.AlertController;
import com.android.settings.R;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
/**
* BluetoothPermissionActivity shows a dialog for accepting incoming
* profile connection request from untrusted devices.
@@ -76,6 +78,7 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getWindow().addPrivateFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
Intent i = getIntent();
String action = i.getAction();
if (!action.equals(BluetoothDevice.ACTION_CONNECTION_ACCESS_REQUEST)) {
diff --git a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
index c5f62b8..5fffa3a 100644
--- a/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
+++ b/src/com/android/settings/bluetooth/BluetoothPermissionRequest.java
@@ -131,6 +131,7 @@
// "Clear All Notifications" button
Intent deleteIntent = new Intent(BluetoothDevice.ACTION_CONNECTION_ACCESS_REPLY);
+ deleteIntent.setPackage("com.android.bluetooth");
deleteIntent.putExtra(BluetoothDevice.EXTRA_DEVICE, mDevice);
deleteIntent.putExtra(BluetoothDevice.EXTRA_CONNECTION_ACCESS_RESULT,
BluetoothDevice.CONNECTION_ACCESS_NO);
diff --git a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
index 2041543..71e65bf 100644
--- a/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
+++ b/src/com/android/settings/fuelgauge/BatteryBroadcastReceiver.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.BatteryManager;
import android.os.PowerManager;
import android.util.Log;
@@ -39,6 +40,7 @@
* 1. Battery level(e.g. 100%->99%)
* 2. Battery status(e.g. plugged->unplugged)
* 3. Battery saver(e.g. off->on)
+ * 4. Battery health(e.g. good->overheat)
*/
public class BatteryBroadcastReceiver extends BroadcastReceiver {
@@ -49,6 +51,7 @@
* Battery level(e.g. 100%->99%)
* Battery status(e.g. plugged->unplugged)
* Battery saver(e.g. off->on)
+ * Battery health(e.g. good->overheat)
*/
public interface OnBatteryChangedListener {
void onBatteryChanged(@BatteryUpdateType int type);
@@ -59,19 +62,23 @@
BatteryUpdateType.BATTERY_LEVEL,
BatteryUpdateType.BATTERY_SAVER,
BatteryUpdateType.BATTERY_STATUS,
+ BatteryUpdateType.BATTERY_HEALTH,
BatteryUpdateType.BATTERY_NOT_PRESENT})
public @interface BatteryUpdateType {
int MANUAL = 0;
int BATTERY_LEVEL = 1;
int BATTERY_SAVER = 2;
int BATTERY_STATUS = 3;
- int BATTERY_NOT_PRESENT = 4;
+ int BATTERY_HEALTH = 4;
+ int BATTERY_NOT_PRESENT = 5;
}
@VisibleForTesting
String mBatteryLevel;
@VisibleForTesting
String mBatteryStatus;
+ @VisibleForTesting
+ int mBatteryHealth;
private OnBatteryChangedListener mBatteryListener;
private Context mContext;
@@ -106,11 +113,15 @@
if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
final String batteryLevel = Utils.getBatteryPercentage(intent);
final String batteryStatus = Utils.getBatteryStatus(mContext, intent);
+ final int batteryHealth = intent.getIntExtra(
+ BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
if (!Utils.isBatteryPresent(intent)) {
Log.w(TAG, "Problem reading the battery meter.");
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_NOT_PRESENT);
} else if (forceUpdate) {
mBatteryListener.onBatteryChanged(BatteryUpdateType.MANUAL);
+ } else if (batteryHealth != mBatteryHealth) {
+ mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_HEALTH);
} else if(!batteryLevel.equals(mBatteryLevel)) {
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_LEVEL);
} else if (!batteryStatus.equals(mBatteryStatus)) {
@@ -118,6 +129,7 @@
}
mBatteryLevel = batteryLevel;
mBatteryStatus = batteryStatus;
+ mBatteryHealth = batteryHealth;
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(intent.getAction())) {
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_SAVER);
}
diff --git a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
index 7b910a1..9066444 100644
--- a/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
+++ b/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceController.java
@@ -124,7 +124,9 @@
public void updateHeaderPreference(BatteryInfo info) {
mBatteryPercentText.setText(formatBatteryPercentageText(info.batteryLevel));
if (!mBatteryStatusFeatureProvider.triggerBatteryStatusUpdate(this, info)) {
- if (info.remainingLabel == null) {
+ if (BatteryUtils.isBatteryDefenderOn(info)) {
+ mSummary1.setText(null);
+ } else if (info.remainingLabel == null) {
mSummary1.setText(info.statusLabel);
} else {
mSummary1.setText(info.remainingLabel);
diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java
index 1935c35..49bdcbb 100644
--- a/src/com/android/settings/fuelgauge/BatteryInfo.java
+++ b/src/com/android/settings/fuelgauge/BatteryInfo.java
@@ -45,6 +45,7 @@
public CharSequence remainingLabel;
public int batteryLevel;
public boolean discharging = true;
+ public boolean isOverheated;
public long remainingTimeUs = 0;
public long averageTimeToDischarge = EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN;
public String batteryPercentString;
@@ -232,6 +233,9 @@
info.batteryPercentString = Utils.formatPercentage(info.batteryLevel);
info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
info.averageTimeToDischarge = estimate.getAverageDischargeTime();
+ info.isOverheated = batteryBroadcast.getIntExtra(
+ BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN)
+ == BatteryManager.BATTERY_HEALTH_OVERHEAT;
info.statusLabel = Utils.getBatteryStatus(context, batteryBroadcast);
if (!info.mCharging) {
@@ -251,7 +255,12 @@
BatteryManager.BATTERY_STATUS_UNKNOWN);
info.discharging = false;
info.suggestionLabel = null;
- if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
+ if (info.isOverheated && status != BatteryManager.BATTERY_STATUS_FULL) {
+ info.remainingLabel = null;
+ int chargingLimitedResId = R.string.power_charging_limited;
+ info.chargeLabel =
+ context.getString(chargingLimitedResId, info.batteryPercentString);
+ } else if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
info.remainingTimeUs = chargeTime;
CharSequence timeString = StringUtil.formatElapsedTime(context,
PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */);
diff --git a/src/com/android/settings/fuelgauge/BatteryUtils.java b/src/com/android/settings/fuelgauge/BatteryUtils.java
index 03387f9..3fc9c5e 100644
--- a/src/com/android/settings/fuelgauge/BatteryUtils.java
+++ b/src/com/android/settings/fuelgauge/BatteryUtils.java
@@ -404,6 +404,13 @@
}
/**
+ * Return {@code true} if battery is overheated and charging.
+ */
+ public static boolean isBatteryDefenderOn(BatteryInfo batteryInfo) {
+ return batteryInfo.isOverheated && !batteryInfo.discharging;
+ }
+
+ /**
* Find package uid from package name
*
* @param packageName used to find the uid
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
index 8d6e07d..0c916b2 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoader.java
@@ -23,6 +23,7 @@
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batterytip.detectors.BatteryDefenderDetector;
import com.android.settings.fuelgauge.batterytip.detectors.EarlyWarningDetector;
import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
@@ -72,6 +73,7 @@
batteryInfo.discharging).detect());
tips.add(new SmartBatteryDetector(policy, context.getContentResolver()).detect());
tips.add(new EarlyWarningDetector(policy, context).detect());
+ tips.add(new BatteryDefenderDetector(batteryInfo).detect());
tips.add(new SummaryDetector(policy, batteryInfo.averageTimeToDischarge).detect());
// Disable this feature now since it introduces false positive cases. We will try to improve
// it in the future.
diff --git a/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java b/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java
index ed06cce..9ef1070 100644
--- a/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java
+++ b/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtils.java
@@ -29,6 +29,7 @@
import com.android.internal.util.CollectionUtils;
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settings.fuelgauge.batterytip.actions.BatteryDefenderAction;
import com.android.settings.fuelgauge.batterytip.actions.BatterySaverAction;
import com.android.settings.fuelgauge.batterytip.actions.BatteryTipAction;
import com.android.settings.fuelgauge.batterytip.actions.OpenBatterySaverAction;
@@ -111,6 +112,8 @@
}
case BatteryTip.TipType.REMOVE_APP_RESTRICTION:
return new UnrestrictAppAction(settingsActivity, (UnrestrictAppTip) batteryTip);
+ case BatteryTip.TipType.BATTERY_DEFENDER:
+ return new BatteryDefenderAction(settingsActivity);
default:
return null;
}
diff --git a/src/com/android/settings/fuelgauge/batterytip/actions/BatteryDefenderAction.java b/src/com/android/settings/fuelgauge/batterytip/actions/BatteryDefenderAction.java
new file mode 100644
index 0000000..b8f5483
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/actions/BatteryDefenderAction.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge.batterytip.actions;
+
+import android.content.Intent;
+
+import com.android.settings.R;
+import com.android.settings.SettingsActivity;
+import com.android.settingslib.HelpUtils;
+
+/**
+ * Action to open the Support Center article
+ */
+public class BatteryDefenderAction extends BatteryTipAction {
+ private SettingsActivity mSettingsActivity;
+
+ public BatteryDefenderAction(SettingsActivity settingsActivity) {
+ super(settingsActivity.getApplicationContext());
+ mSettingsActivity = settingsActivity;
+ }
+
+ /**
+ * Handle the action when user clicks positive button
+ */
+ @Override
+ public void handlePositiveAction(int metricsKey) {
+ final Intent intent = HelpUtils.getHelpIntent(
+ mContext,
+ mContext.getString(R.string.help_url_battery_defender),
+ getClass().getName());
+ if (intent != null) {
+ mSettingsActivity.startActivityForResult(intent, 0);
+ }
+ // TODO(b/173985153): Add logging enums for Battery Defender.
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
new file mode 100644
index 0000000..86744f5
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetector.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge.batterytip.detectors;
+
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.BatteryUtils;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryDefenderTip;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+
+/**
+ * Detect whether the battery is overheated
+ */
+public class BatteryDefenderDetector implements BatteryTipDetector {
+ private BatteryInfo mBatteryInfo;
+
+ public BatteryDefenderDetector(BatteryInfo batteryInfo) {
+ mBatteryInfo = batteryInfo;
+ }
+
+ @Override
+ public BatteryTip detect() {
+ final int state =
+ BatteryUtils.isBatteryDefenderOn(mBatteryInfo)
+ ? BatteryTip.StateType.NEW
+ : BatteryTip.StateType.INVISIBLE;
+ return new BatteryDefenderTip(state);
+ }
+}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
new file mode 100644
index 0000000..cd23e50
--- /dev/null
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTip.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge.batterytip.tips;
+
+import android.content.Context;
+import android.os.Parcel;
+
+import com.android.settings.R;
+import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
+
+/**
+ * Tip to show current battery is overheated
+ */
+public class BatteryDefenderTip extends BatteryTip {
+
+ public BatteryDefenderTip(@StateType int state) {
+ super(TipType.BATTERY_DEFENDER, state, false /* showDialog */);
+ }
+
+ private BatteryDefenderTip(Parcel in) {
+ super(in);
+ }
+
+ @Override
+ public CharSequence getTitle(Context context) {
+ return context.getString(R.string.battery_tip_limited_temporarily_title);
+ }
+
+ @Override
+ public CharSequence getSummary(Context context) {
+ return context.getString(R.string.battery_tip_limited_temporarily_summary);
+ }
+
+ @Override
+ public int getIconId() {
+ return R.drawable.ic_battery_status_good_24dp;
+ }
+
+ @Override
+ public void updateState(BatteryTip tip) {
+ mState = tip.mState;
+ }
+
+ @Override
+ public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) {
+ // TODO(b/173985153): Add logging enums for Battery Defender.
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ public BatteryTip createFromParcel(Parcel in) {
+ return new BatteryDefenderTip(in);
+ }
+
+ public BatteryTip[] newArray(int size) {
+ return new BatteryDefenderTip[size];
+ }
+ };
+
+}
diff --git a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
index ebc4939..13015a7 100644
--- a/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
+++ b/src/com/android/settings/fuelgauge/batterytip/tips/BatteryTip.java
@@ -17,7 +17,6 @@
package com.android.settings.fuelgauge.batterytip.tips;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.SparseIntArray;
@@ -58,7 +57,8 @@
TipType.APP_RESTRICTION,
TipType.REDUCED_BATTERY,
TipType.LOW_BATTERY,
- TipType.REMOVE_APP_RESTRICTION})
+ TipType.REMOVE_APP_RESTRICTION,
+ TipType.BATTERY_DEFENDER})
public @interface TipType {
int SMART_BATTERY_MANAGER = 0;
int APP_RESTRICTION = 1;
@@ -68,20 +68,22 @@
int LOW_BATTERY = 5;
int SUMMARY = 6;
int REMOVE_APP_RESTRICTION = 7;
+ int BATTERY_DEFENDER = 8;
}
@VisibleForTesting
static final SparseIntArray TIP_ORDER;
static {
TIP_ORDER = new SparseIntArray();
- TIP_ORDER.append(TipType.APP_RESTRICTION, 0);
- TIP_ORDER.append(TipType.BATTERY_SAVER, 1);
- TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 2);
- TIP_ORDER.append(TipType.LOW_BATTERY, 3);
- TIP_ORDER.append(TipType.SUMMARY, 4);
- TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 5);
- TIP_ORDER.append(TipType.REDUCED_BATTERY, 6);
- TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 7);
+ TIP_ORDER.append(TipType.BATTERY_DEFENDER, 0);
+ TIP_ORDER.append(TipType.APP_RESTRICTION, 1);
+ TIP_ORDER.append(TipType.BATTERY_SAVER, 2);
+ TIP_ORDER.append(TipType.HIGH_DEVICE_USAGE, 3);
+ TIP_ORDER.append(TipType.LOW_BATTERY, 4);
+ TIP_ORDER.append(TipType.SUMMARY, 5);
+ TIP_ORDER.append(TipType.SMART_BATTERY_MANAGER, 6);
+ TIP_ORDER.append(TipType.REDUCED_BATTERY, 7);
+ TIP_ORDER.append(TipType.REMOVE_APP_RESTRICTION, 8);
}
private static final String KEY_PREFIX = "key_battery_tip";
diff --git a/src/com/android/settings/media/MediaDeviceUpdateWorker.java b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
index 1288cf5..f8e40cd 100644
--- a/src/com/android/settings/media/MediaDeviceUpdateWorker.java
+++ b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
@@ -30,6 +30,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.text.TextUtils;
+import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -51,6 +52,9 @@
public class MediaDeviceUpdateWorker extends SliceBackgroundWorker
implements LocalMediaManager.DeviceCallback {
+ private static final String TAG = "MediaDeviceUpdateWorker";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
protected final Context mContext;
protected final Collection<MediaDevice> mMediaDevices = new CopyOnWriteArrayList<>();
private final DevicesChangedBroadcastReceiver mReceiver;
@@ -213,6 +217,10 @@
final List<RoutingSessionInfo> sessionInfos = new ArrayList<>();
for (RoutingSessionInfo info : mLocalMediaManager.getActiveMediaSession()) {
if (!info.isSystemSession()) {
+ if (DEBUG) {
+ Log.d(TAG, "getActiveRemoteMediaDevice() info : " + info.toString()
+ + ", package name : " + info.getClientPackageName());
+ }
sessionInfos.add(info);
}
}
diff --git a/src/com/android/settings/media/MediaOutputIndicatorWorker.java b/src/com/android/settings/media/MediaOutputIndicatorWorker.java
index f094d47..ef3a7bc 100644
--- a/src/com/android/settings/media/MediaOutputIndicatorWorker.java
+++ b/src/com/android/settings/media/MediaOutputIndicatorWorker.java
@@ -25,7 +25,6 @@
import android.media.AudioManager;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
-import android.media.session.PlaybackState;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
@@ -53,6 +52,7 @@
LocalMediaManager.DeviceCallback {
private static final String TAG = "MediaOutputIndWorker";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final DevicesChangedBroadcastReceiver mReceiver;
private final Context mContext;
@@ -127,24 +127,8 @@
@Nullable
MediaController getActiveLocalMediaController() {
- final MediaSessionManager mMediaSessionManager = mContext.getSystemService(
- MediaSessionManager.class);
-
- for (MediaController controller : mMediaSessionManager.getActiveSessions(null)) {
- final MediaController.PlaybackInfo pi = controller.getPlaybackInfo();
- if (pi == null) {
- return null;
- }
- final PlaybackState playbackState = controller.getPlaybackState();
- if (playbackState == null) {
- return null;
- }
- if (pi.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
- && playbackState.getState() == PlaybackState.STATE_PLAYING) {
- return controller;
- }
- }
- return null;
+ return MediaOutputUtils.getActiveLocalMediaController(mContext.getSystemService(
+ MediaSessionManager.class));
}
@Override
diff --git a/src/com/android/settings/media/MediaOutputUtils.java b/src/com/android/settings/media/MediaOutputUtils.java
new file mode 100644
index 0000000..977c517
--- /dev/null
+++ b/src/com/android/settings/media/MediaOutputUtils.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.media;
+
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import com.android.settings.sound.MediaOutputPreferenceController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utilities that can be shared between {@link MediaOutputIndicatorWorker} and
+ * {@link MediaOutputPreferenceController}.
+ */
+public class MediaOutputUtils {
+
+ private static final String TAG = "MediaOutputUtils";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ /**
+ * Returns a {@link MediaController} that state is playing and type is local playback,
+ * and also have active sessions.
+ */
+ @Nullable
+ public static MediaController getActiveLocalMediaController(
+ MediaSessionManager mediaSessionManager) {
+
+ MediaController localController = null;
+ final List<String> remoteMediaSessionLists = new ArrayList<>();
+ for (MediaController controller : mediaSessionManager.getActiveSessions(null)) {
+ final MediaController.PlaybackInfo pi = controller.getPlaybackInfo();
+ if (pi == null) {
+ // do nothing
+ continue;
+ }
+ final PlaybackState playbackState = controller.getPlaybackState();
+ if (playbackState == null) {
+ // do nothing
+ continue;
+ }
+ if (DEBUG) {
+ Log.d(TAG, "getActiveLocalMediaController() package name : "
+ + controller.getPackageName()
+ + ", play back type : " + pi.getPlaybackType() + ", play back state : "
+ + playbackState.getState());
+ }
+ if (playbackState.getState() != PlaybackState.STATE_PLAYING) {
+ // do nothing
+ continue;
+ }
+ if (pi.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE) {
+ if (localController != null && TextUtils.equals(localController.getPackageName(),
+ controller.getPackageName())) {
+ localController = null;
+ }
+ if (!remoteMediaSessionLists.contains(controller.getPackageName())) {
+ remoteMediaSessionLists.add(controller.getPackageName());
+ }
+ continue;
+ }
+ if (pi.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL) {
+ if (localController == null
+ && !remoteMediaSessionLists.contains(controller.getPackageName())) {
+ localController = controller;
+ }
+ }
+ }
+ return localController;
+ }
+}
diff --git a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
index 8677c02..a7d9f68 100644
--- a/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
+++ b/src/com/android/settings/notification/NotificationAccessConfirmationActivity.java
@@ -17,6 +17,8 @@
package com.android.settings.notification;
+import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
import static com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_COMPONENT_NAME;
import static com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_PACKAGE_TITLE;
import static com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_USER_ID;
@@ -55,6 +57,8 @@
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+
mNm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mComponentName = getIntent().getParcelableExtra(EXTRA_COMPONENT_NAME);
diff --git a/src/com/android/settings/notification/RemoteVolumeGroupController.java b/src/com/android/settings/notification/RemoteVolumeGroupController.java
index eb72c59..933e8b4 100644
--- a/src/com/android/settings/notification/RemoteVolumeGroupController.java
+++ b/src/com/android/settings/notification/RemoteVolumeGroupController.java
@@ -102,43 +102,80 @@
mLocalMediaManager.stopScan();
}
- private void refreshPreference() {
- mPreferenceCategory.removeAll();
+ private synchronized void refreshPreference() {
if (!isAvailable()) {
mPreferenceCategory.setVisible(false);
return;
}
final CharSequence castVolume = mContext.getText(R.string.remote_media_volume_option_title);
mPreferenceCategory.setVisible(true);
-
for (RoutingSessionInfo info : mRoutingSessionInfos) {
- if (mPreferenceCategory.findPreference(info.getId()) != null) {
- continue;
+ final CharSequence appName = Utils.getApplicationLabel(mContext,
+ info.getClientPackageName());
+ RemoteVolumeSeekBarPreference seekBarPreference = mPreferenceCategory.findPreference(
+ info.getId());
+ if (seekBarPreference != null) {
+ // Update slider
+ if (seekBarPreference.getProgress() != info.getVolume()) {
+ seekBarPreference.setProgress(info.getVolume());
+ }
+ } else {
+ // Add slider
+ seekBarPreference = new RemoteVolumeSeekBarPreference(mContext);
+ seekBarPreference.setKey(info.getId());
+ seekBarPreference.setTitle(castVolume);
+ seekBarPreference.setMax(info.getVolumeMax());
+ seekBarPreference.setProgress(info.getVolume());
+ seekBarPreference.setMin(0);
+ seekBarPreference.setOnPreferenceChangeListener(this);
+ seekBarPreference.setIcon(R.drawable.ic_volume_remote);
+ mPreferenceCategory.addPreference(seekBarPreference);
}
- final CharSequence appName = Utils.getApplicationLabel(
- mContext, info.getClientPackageName());
- final CharSequence outputTitle = mContext.getString(R.string.media_output_label_title,
- appName);
- // Add slider
- final RemoteVolumeSeekBarPreference seekBarPreference =
- new RemoteVolumeSeekBarPreference(mContext);
- seekBarPreference.setKey(info.getId());
- seekBarPreference.setTitle(castVolume);
- seekBarPreference.setMax(info.getVolumeMax());
- seekBarPreference.setProgress(info.getVolume());
- seekBarPreference.setMin(0);
- seekBarPreference.setOnPreferenceChangeListener(this);
- seekBarPreference.setIcon(R.drawable.ic_volume_remote);
- mPreferenceCategory.addPreference(seekBarPreference);
- // Add output indicator
+
+ Preference switcherPreference = mPreferenceCategory.findPreference(
+ SWITCHER_PREFIX + info.getId());
final boolean isMediaOutputDisabled = Utils.isMediaOutputDisabled(
mRouterManager, info.getClientPackageName());
- final Preference preference = new Preference(mContext);
- preference.setKey(SWITCHER_PREFIX + info.getId());
- preference.setTitle(isMediaOutputDisabled ? appName : outputTitle);
- preference.setSummary(info.getName());
- preference.setEnabled(!isMediaOutputDisabled);
- mPreferenceCategory.addPreference(preference);
+ final CharSequence outputTitle = mContext.getString(R.string.media_output_label_title,
+ appName);
+ if (switcherPreference != null) {
+ // Update output indicator
+ switcherPreference.setTitle(isMediaOutputDisabled ? appName : outputTitle);
+ switcherPreference.setSummary(info.getName());
+ switcherPreference.setEnabled(!isMediaOutputDisabled);
+ } else {
+ // Add output indicator
+ switcherPreference = new Preference(mContext);
+ switcherPreference.setKey(SWITCHER_PREFIX + info.getId());
+ switcherPreference.setTitle(isMediaOutputDisabled ? appName : outputTitle);
+ switcherPreference.setSummary(info.getName());
+ switcherPreference.setEnabled(!isMediaOutputDisabled);
+ mPreferenceCategory.addPreference(switcherPreference);
+ }
+ }
+
+ // Check and remove non-active session preference
+ // There is a pair of preferences for each session. First one is a seekBar preference.
+ // The second one shows the session information and provide an entry-point to launch output
+ // switcher. It is unnecessary to go through all preferences. It is fine ignore the second
+ // preference and only to check the seekBar's key value.
+ for (int i = 0; i < mPreferenceCategory.getPreferenceCount(); i = i + 2) {
+ final Preference preference = mPreferenceCategory.getPreference(i);
+ boolean isActive = false;
+ for (RoutingSessionInfo info : mRoutingSessionInfos) {
+ if (TextUtils.equals(preference.getKey(), info.getId())) {
+ isActive = true;
+ break;
+ }
+ }
+ if (isActive) {
+ continue;
+ }
+ final Preference switcherPreference = mPreferenceCategory.getPreference(i + 1);
+ if (switcherPreference != null) {
+ mPreferenceCategory.removePreference(preference);
+ mPreferenceCategory.removePreference(switcherPreference);
+ }
}
}
@@ -181,8 +218,10 @@
// Preference group is not ready.
return;
}
- initRemoteMediaSession();
- refreshPreference();
+ ThreadUtils.postOnMainThread(() -> {
+ initRemoteMediaSession();
+ refreshPreference();
+ });
}
@Override
diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java
index 7c3d2b1..40a4d56 100644
--- a/src/com/android/settings/sound/MediaOutputPreferenceController.java
+++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java
@@ -22,14 +22,13 @@
import android.media.AudioManager;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
-import android.media.session.PlaybackState;
import android.text.TextUtils;
-import androidx.annotation.Nullable;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
+import com.android.settings.media.MediaOutputUtils;
import com.android.settingslib.Utils;
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.HearingAidProfile;
@@ -51,7 +50,8 @@
public MediaOutputPreferenceController(Context context, String key) {
super(context, key);
- mMediaController = getActiveLocalMediaController();
+ mMediaController = MediaOutputUtils.getActiveLocalMediaController(context.getSystemService(
+ MediaSessionManager.class));
}
@Override
@@ -144,26 +144,4 @@
}
return false;
}
-
- @Nullable
- MediaController getActiveLocalMediaController() {
- final MediaSessionManager mMediaSessionManager = mContext.getSystemService(
- MediaSessionManager.class);
-
- for (MediaController controller : mMediaSessionManager.getActiveSessions(null)) {
- final MediaController.PlaybackInfo pi = controller.getPlaybackInfo();
- if (pi == null) {
- return null;
- }
- final PlaybackState playbackState = controller.getPlaybackState();
- if (playbackState == null) {
- return null;
- }
- if (pi.getPlaybackType() == MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
- && playbackState.getState() == PlaybackState.STATE_PLAYING) {
- return controller;
- }
- }
- return null;
- }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
index 742daf2..a072988 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryBroadcastReceiverTest.java
@@ -66,6 +66,7 @@
mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(mContext);
mBatteryBroadcastReceiver.mBatteryLevel = BATTERY_INIT_LEVEL;
mBatteryBroadcastReceiver.mBatteryStatus = BATTERY_INIT_STATUS;
+ mBatteryBroadcastReceiver.mBatteryHealth = BatteryManager.BATTERY_HEALTH_UNKNOWN;
mBatteryBroadcastReceiver.setBatteryChangedListener(mBatteryListener);
mChargingIntent = new Intent(Intent.ACTION_BATTERY_CHANGED);
@@ -95,6 +96,21 @@
BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
BatteryFixSliceTest.ShadowBatteryTipLoader.class
})
+ public void testOnReceive_batteryHealthChanged_dataUpdated() {
+ mChargingIntent
+ .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+ mBatteryBroadcastReceiver.onReceive(mContext, mChargingIntent);
+
+ assertThat(mBatteryBroadcastReceiver.mBatteryHealth)
+ .isEqualTo(BatteryManager.BATTERY_HEALTH_OVERHEAT);
+ verify(mBatteryListener).onBatteryChanged(BatteryUpdateType.BATTERY_HEALTH);
+ }
+
+ @Test
+ @Config(shadows = {
+ BatteryFixSliceTest.ShadowBatteryStatsHelperLoader.class,
+ BatteryFixSliceTest.ShadowBatteryTipLoader.class
+ })
public void onReceive_batteryNotPresent_shouldShowHelpMessage() {
mChargingIntent.putExtra(BatteryManager.EXTRA_PRESENT, false);
@@ -131,6 +147,8 @@
assertThat(mBatteryBroadcastReceiver.mBatteryLevel).isEqualTo(batteryLevel);
assertThat(mBatteryBroadcastReceiver.mBatteryStatus).isEqualTo(batteryStatus);
+ assertThat(mBatteryBroadcastReceiver.mBatteryHealth)
+ .isEqualTo(BatteryManager.BATTERY_HEALTH_UNKNOWN);
verify(mBatteryListener, never()).onBatteryChanged(anyInt());
}
@@ -149,6 +167,8 @@
.isEqualTo(Utils.getBatteryPercentage(mChargingIntent));
assertThat(mBatteryBroadcastReceiver.mBatteryStatus)
.isEqualTo(Utils.getBatteryStatus(mContext, mChargingIntent));
+ assertThat(mBatteryBroadcastReceiver.mBatteryHealth)
+ .isEqualTo(BatteryManager.BATTERY_HEALTH_UNKNOWN);
// 2 times because register will force update the battery
verify(mBatteryListener, times(2)).onBatteryChanged(BatteryUpdateType.MANUAL);
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
index a6cf653..ac3c8f9 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryHeaderPreferenceControllerTest.java
@@ -176,6 +176,15 @@
}
@Test
+ public void updatePreference_isOverheat_showEmptyText() {
+ mBatteryInfo.isOverheated = true;
+
+ mController.updateHeaderPreference(mBatteryInfo);
+
+ assertThat(mSummary.getText().toString().isEmpty()).isTrue();
+ }
+
+ @Test
public void onStart_shouldStyleActionBar() {
when(mEntityHeaderController.setRecyclerView(nullable(RecyclerView.class), eq(mLifecycle)))
.thenReturn(mEntityHeaderController);
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
index 3cbc58a..d0af982 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryInfoTest.java
@@ -246,6 +246,22 @@
assertThat(info.chargeLabel).isEqualTo("100%");
}
+ @Test
+ public void testGetBatteryInfo_chargingWithOverheated_updateChargeLabel() {
+ doReturn(TEST_CHARGE_TIME_REMAINING)
+ .when(mBatteryStats)
+ .computeChargeTimeRemaining(anyLong());
+ mChargingBatteryBroadcast
+ .putExtra(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_OVERHEAT);
+
+ BatteryInfo info = BatteryInfo.getBatteryInfo(mContext, mChargingBatteryBroadcast,
+ mBatteryStats, DUMMY_ESTIMATE, SystemClock.elapsedRealtime() * 1000,
+ false /* shortString */);
+
+ assertThat(info.isOverheated).isTrue();
+ assertThat(info.chargeLabel).isEqualTo("50% - Battery limited temporarily");
+ }
+
// Make our battery stats return a sequence of battery events.
private void mockBatteryStatsHistory() {
// Mock out new data every time start...Locked is called.
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
index 0faddc3..5d985fd 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryUtilsTest.java
@@ -144,6 +144,8 @@
@Mock
private BatterySipper mIdleBatterySipper;
@Mock
+ private BatteryInfo mBatteryInfo;
+ @Mock
private Bundle mBundle;
@Mock
private UserManager mUserManager;
@@ -754,4 +756,36 @@
assertThat(estimate.isBasedOnUsage()).isTrue();
assertThat(estimate.getAverageDischargeTime()).isEqualTo(1000);
}
+
+ @Test
+ public void testIsBatteryDefenderOn_isOverheatedAndIsCharging_returnTrue() {
+ mBatteryInfo.isOverheated = true;
+ mBatteryInfo.discharging = false;
+
+ assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isTrue();
+ }
+
+ @Test
+ public void testIsBatteryDefenderOn_isOverheatedAndDischarging_returnFalse() {
+ mBatteryInfo.isOverheated = true;
+ mBatteryInfo.discharging = true;
+
+ assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isFalse();
+ }
+
+ @Test
+ public void testIsBatteryDefenderOn_notOverheatedAndDischarging_returnFalse() {
+ mBatteryInfo.isOverheated = false;
+ mBatteryInfo.discharging = true;
+
+ assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isFalse();
+ }
+
+ @Test
+ public void testIsBatteryDefenderOn_notOverheatedAndIsCharging_returnFalse() {
+ mBatteryInfo.isOverheated = false;
+ mBatteryInfo.discharging = false;
+
+ assertThat(mBatteryUtils.isBatteryDefenderOn(mBatteryInfo)).isFalse();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
index 116033b..8cc17d8 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipLoaderTest.java
@@ -50,6 +50,7 @@
public class BatteryTipLoaderTest {
private static final int[] TIP_ORDER = {
+ BatteryTip.TipType.BATTERY_DEFENDER,
BatteryTip.TipType.BATTERY_SAVER,
BatteryTip.TipType.HIGH_DEVICE_USAGE,
BatteryTip.TipType.LOW_BATTERY,
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java
index 275bfe0..6199788 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/BatteryTipUtilsTest.java
@@ -23,10 +23,12 @@
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
+import com.android.settings.fuelgauge.batterytip.actions.BatteryDefenderAction;
import com.android.settings.fuelgauge.batterytip.actions.BatterySaverAction;
import com.android.settings.fuelgauge.batterytip.actions.OpenBatterySaverAction;
import com.android.settings.fuelgauge.batterytip.actions.OpenRestrictAppFragmentAction;
import com.android.settings.fuelgauge.batterytip.actions.RestrictAppAction;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryDefenderTip;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.EarlyWarningTip;
import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip;
@@ -53,6 +55,7 @@
private RestrictAppTip mRestrictAppTip;
private EarlyWarningTip mEarlyWarningTip;
private LowBatteryTip mLowBatteryTip;
+ private BatteryDefenderTip mBatteryDefenderTip;
@Before
public void setUp() {
@@ -67,6 +70,7 @@
mLowBatteryTip = spy(
new LowBatteryTip(BatteryTip.StateType.NEW, false /* powerSaveModeOn */,
"" /* summary */));
+ mBatteryDefenderTip = spy(new BatteryDefenderTip(BatteryTip.StateType.NEW));
}
@Test
@@ -116,4 +120,13 @@
assertThat(BatteryTipUtils.getActionForBatteryTip(mLowBatteryTip, mSettingsActivity,
mFragment)).isInstanceOf(OpenBatterySaverAction.class);
}
+
+ @Test
+ public void
+ testGetActionForBatteryTip_typeBatteryDefenderStateNew_returnActionBatteryDefender() {
+ when(mBatteryDefenderTip.getState()).thenReturn(BatteryTip.StateType.NEW);
+
+ assertThat(BatteryTipUtils.getActionForBatteryTip(mBatteryDefenderTip, mSettingsActivity,
+ mFragment)).isInstanceOf(BatteryDefenderAction.class);
+ }
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
new file mode 100644
index 0000000..a1f9d1f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/detectors/BatteryDefenderDetectorTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.fuelgauge.batterytip.detectors;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.android.settings.fuelgauge.BatteryInfo;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class BatteryDefenderDetectorTest {
+
+ @Mock
+ private BatteryInfo mBatteryInfo;
+ private BatteryDefenderDetector mBatteryDefenderDetector;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mBatteryInfo.discharging = false;
+
+ mBatteryDefenderDetector = new BatteryDefenderDetector(mBatteryInfo);
+ }
+
+ @Test
+ public void testDetect_notOverheated_tipInvisible() {
+ mBatteryInfo.isOverheated = false;
+
+ assertThat(mBatteryDefenderDetector.detect().isVisible()).isFalse();
+ }
+
+ @Test
+ public void testDetect_isOverheated_tipNew() {
+ mBatteryInfo.isOverheated = true;
+
+ assertThat(mBatteryDefenderDetector.detect().getState())
+ .isEqualTo(BatteryTip.StateType.NEW);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
new file mode 100644
index 0000000..c6eb15d
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batterytip/tips/BatteryDefenderTipTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.fuelgauge.batterytip.tips;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import com.android.settings.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class BatteryDefenderTipTest {
+
+ private Context mContext;
+ private BatteryDefenderTip mBatteryDefenderTip;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = RuntimeEnvironment.application;
+ mBatteryDefenderTip = new BatteryDefenderTip(BatteryTip.StateType.NEW);
+ }
+
+ @Test
+ public void getTitle_showTitle() {
+ assertThat(mBatteryDefenderTip.getTitle(mContext))
+ .isEqualTo(mContext.getString(R.string.battery_tip_limited_temporarily_title));
+ }
+
+ @Test
+ public void getSummary_showSummary() {
+ assertThat(mBatteryDefenderTip.getSummary(mContext))
+ .isEqualTo(mContext.getString(R.string.battery_tip_limited_temporarily_summary));
+ }
+
+ @Test
+ public void getIcon_showIcon() {
+ assertThat(mBatteryDefenderTip.getIconId())
+ .isEqualTo(R.drawable.ic_battery_status_good_24dp);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java
index d9b2247..1970f6c 100644
--- a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java
@@ -261,4 +261,29 @@
assertThat(mMediaOutputIndicatorWorker.getActiveLocalMediaController()).isNull();
}
+
+ @Test
+ public void getActiveLocalMediaController_bothHaveRemoteMediaAndLocalMedia_returnNull() {
+ final MediaController.PlaybackInfo playbackInfo = new MediaController.PlaybackInfo(
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
+ VolumeProvider.VOLUME_CONTROL_ABSOLUTE,
+ 100,
+ 10,
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(),
+ null);
+ final PlaybackState playbackState = new PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PLAYING, 0, 1)
+ .build();
+ final MediaController remoteMediaController = mock(MediaController.class);
+
+ mMediaControllers.add(remoteMediaController);
+ initPlayback();
+
+ when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
+ when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
+ when(remoteMediaController.getPlaybackInfo()).thenReturn(playbackInfo);
+ when(remoteMediaController.getPlaybackState()).thenReturn(playbackState);
+
+ assertThat(mMediaOutputIndicatorWorker.getActiveLocalMediaController()).isNull();
+ }
}
diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputUtilsTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputUtilsTest.java
new file mode 100644
index 0000000..dea6a2c
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputUtilsTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.media;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.media.AudioAttributes;
+import android.media.VolumeProvider;
+import android.media.session.MediaController;
+import android.media.session.MediaSessionManager;
+import android.media.session.PlaybackState;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(RobolectricTestRunner.class)
+public class MediaOutputUtilsTest {
+
+ @Mock
+ private MediaSessionManager mMediaSessionManager;
+ @Mock
+ private MediaController mMediaController;
+
+ private Context mContext;
+ private List<MediaController> mMediaControllers = new ArrayList<>();
+ private PlaybackState mPlaybackState;
+ private MediaController.PlaybackInfo mPlaybackInfo;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContext = spy(RuntimeEnvironment.application);
+ doReturn(mMediaSessionManager).when(mContext).getSystemService(MediaSessionManager.class);
+ mMediaControllers.add(mMediaController);
+ doReturn(mMediaControllers).when(mMediaSessionManager).getActiveSessions(any());
+ }
+
+ @Test
+ public void getActiveLocalMediaController_localMediaPlaying_returnController() {
+ initPlayback();
+
+ when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
+ when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
+
+ assertThat(MediaOutputUtils.getActiveLocalMediaController(mMediaSessionManager)).isEqualTo(
+ mMediaController);
+ }
+
+ @Test
+ public void getActiveLocalMediaController_remoteMediaPlaying_returnNull() {
+ mPlaybackInfo = new MediaController.PlaybackInfo(
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
+ VolumeProvider.VOLUME_CONTROL_ABSOLUTE,
+ 100,
+ 10,
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(),
+ null);
+ mPlaybackState = new PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PLAYING, 0, 1)
+ .build();
+
+ when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
+ when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
+
+ assertThat(MediaOutputUtils.getActiveLocalMediaController(mMediaSessionManager)).isNull();
+ }
+
+ @Test
+ public void getActiveLocalMediaController_localMediaStopped_returnNull() {
+ mPlaybackInfo = new MediaController.PlaybackInfo(
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
+ VolumeProvider.VOLUME_CONTROL_ABSOLUTE,
+ 100,
+ 10,
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(),
+ null);
+ mPlaybackState = new PlaybackState.Builder()
+ .setState(PlaybackState.STATE_STOPPED, 0, 1)
+ .build();
+
+ when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
+ when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
+
+ assertThat(MediaOutputUtils.getActiveLocalMediaController(mMediaSessionManager)).isNull();
+ }
+
+ @Test
+ public void getActiveLocalMediaController_bothHaveRemoteMediaAndLocalMedia_returnNull() {
+ mMediaControllers.clear();
+ final MediaController.PlaybackInfo playbackInfo = new MediaController.PlaybackInfo(
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
+ VolumeProvider.VOLUME_CONTROL_ABSOLUTE,
+ 100,
+ 10,
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(),
+ null);
+ final PlaybackState playbackState = new PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PLAYING, 0, 1)
+ .build();
+ final MediaController remoteMediaController = mock(MediaController.class);
+
+ mMediaControllers.add(remoteMediaController);
+ mMediaControllers.add(mMediaController);
+ initPlayback();
+
+ when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
+ when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
+ when(remoteMediaController.getPlaybackInfo()).thenReturn(playbackInfo);
+ when(remoteMediaController.getPlaybackState()).thenReturn(playbackState);
+
+ assertThat(MediaOutputUtils.getActiveLocalMediaController(mMediaSessionManager)).isNull();
+ }
+
+ @Test
+ public void getActiveLocalMediaController_bothHaveLocalMediaAndRemoteMedia_returnNull() {
+ final MediaController.PlaybackInfo playbackInfo = new MediaController.PlaybackInfo(
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE,
+ VolumeProvider.VOLUME_CONTROL_ABSOLUTE,
+ 100,
+ 10,
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(),
+ null);
+ final PlaybackState playbackState = new PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PLAYING, 0, 1)
+ .build();
+ final MediaController remoteMediaController = mock(MediaController.class);
+
+ mMediaControllers.add(remoteMediaController);
+ initPlayback();
+
+ when(mMediaController.getPlaybackInfo()).thenReturn(mPlaybackInfo);
+ when(mMediaController.getPlaybackState()).thenReturn(mPlaybackState);
+ when(remoteMediaController.getPlaybackInfo()).thenReturn(playbackInfo);
+ when(remoteMediaController.getPlaybackState()).thenReturn(playbackState);
+
+ assertThat(MediaOutputUtils.getActiveLocalMediaController(mMediaSessionManager)).isNull();
+ }
+
+ private void initPlayback() {
+ mPlaybackInfo = new MediaController.PlaybackInfo(
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL,
+ VolumeProvider.VOLUME_CONTROL_ABSOLUTE,
+ 100,
+ 10,
+ new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_MEDIA).build(),
+ null);
+ mPlaybackState = new PlaybackState.Builder()
+ .setState(PlaybackState.STATE_PLAYING, 0, 1)
+ .build();
+ }
+}