diff options
118 files changed, 1489 insertions, 979 deletions
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 2a3f916dcdec..e8e5a514d15f 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -1970,8 +1970,8 @@ <string name="usb_mtp_launch_notification_description" msgid="6942535713629852684">"Presiona para ver archivos"</string> <string name="pin_target" msgid="8036028973110156895">"Fijar"</string> <string name="pin_specific_target" msgid="7824671240625957415">"Fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string> - <string name="unpin_target" msgid="3963318576590204447">"No fijar"</string> - <string name="unpin_specific_target" msgid="3859828252160908146">"No fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string> + <string name="unpin_target" msgid="3963318576590204447">"Dejar de fijar"</string> + <string name="unpin_specific_target" msgid="3859828252160908146">"Dejar de fijar <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="app_info" msgid="6113278084877079851">"Información de apps"</string> <string name="negative_duration" msgid="1938335096972945232">"−<xliff:g id="TIME">%1$s</xliff:g>"</string> <string name="demo_starting_message" msgid="6577581216125805905">"Iniciando demostración…"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 79faaac94919..0daa3249cc0c 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -1139,7 +1139,7 @@ <string name="copy" msgid="5472512047143665218">"कॉपी करें"</string> <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"क्लिपबोर्ड पर कॉपी नहीं हो सका"</string> <string name="paste" msgid="461843306215520225">"चिपकाएं"</string> - <string name="paste_as_plain_text" msgid="7664800665823182587">"सादे पाठ के रूप में चिपकाएं"</string> + <string name="paste_as_plain_text" msgid="7664800665823182587">"सादे टेक्स्ट के रूप में चिपकाएं"</string> <string name="replace" msgid="7842675434546657444">"बदलें•"</string> <string name="delete" msgid="1514113991712129054">"मिटाएं"</string> <string name="copyUrl" msgid="6229645005987260230">"यूआरएल को कॉपी करें"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 9ab64e6f26df..d11eca61752f 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -252,7 +252,7 @@ <string name="bugreport_message" msgid="5212529146119624326">"현재 기기 상태에 대한 정보를 수집하여 이메일 메시지로 전송합니다. 버그 신고를 시작하여 전송할 준비가 되려면 약간 시간이 걸립니다."</string> <string name="bugreport_option_interactive_title" msgid="7968287837902871289">"대화형 보고서"</string> <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"대부분의 경우 이 옵션을 사용합니다. 신고 진행 상황을 추적하고 문제에 대한 세부정보를 입력하고 스크린샷을 찍을 수 있습니다. 신고하기에 시간이 너무 오래 걸리고 사용 빈도가 낮은 일부 섹션을 생략할 수 있습니다."</string> - <string name="bugreport_option_full_title" msgid="7681035745950045690">"전체 보고서"</string> + <string name="bugreport_option_full_title" msgid="7681035745950045690">"전체 신고"</string> <string name="bugreport_option_full_summary" msgid="1975130009258435885">"기기가 응답하지 않거나 너무 느리거나 모든 보고서 섹션이 필요한 경우 이 옵션을 사용하여 시스템 방해를 최소화합니다. 세부정보를 추가하거나 스크린샷을 추가로 찍을 수 없습니다."</string> <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{버그 신고 스크린샷을 #초 후에 찍습니다.}other{버그 신고 스크린샷을 #초 후에 찍습니다.}}"</string> <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"버그 신고용 스크린샷 촬영 완료"</string> diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml index 0fdfed86b29e..17b1d1bdbff1 100644 --- a/libs/WindowManager/Shell/res/values-am/strings.xml +++ b/libs/WindowManager/Shell/res/values-am/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"አስፋ"</string> <string name="minimize_button_text" msgid="271592547935841753">"አሳንስ"</string> <string name="close_button_text" msgid="2913281996024033299">"ዝጋ"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"ተመለስ"</string> + <string name="handle_text" msgid="1766582106752184456">"መያዣ"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml index 351e1928a260..2babc3ea5fcd 100644 --- a/libs/WindowManager/Shell/res/values-ar/strings.xml +++ b/libs/WindowManager/Shell/res/values-ar/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"تكبير"</string> <string name="minimize_button_text" msgid="271592547935841753">"تصغير"</string> <string name="close_button_text" msgid="2913281996024033299">"إغلاق"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"رجوع"</string> + <string name="handle_text" msgid="1766582106752184456">"مقبض"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml index 765aaba4d23c..fe43cd69110f 100644 --- a/libs/WindowManager/Shell/res/values-as/strings.xml +++ b/libs/WindowManager/Shell/res/values-as/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"সৰ্বাধিক মাত্ৰালৈ বঢ়াওক"</string> <string name="minimize_button_text" msgid="271592547935841753">"মিনিমাইজ কৰক"</string> <string name="close_button_text" msgid="2913281996024033299">"বন্ধ কৰক"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"উভতি যাওক"</string> + <string name="handle_text" msgid="1766582106752184456">"হেণ্ডেল"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml index 0ec5db185e34..c22f5425048e 100644 --- a/libs/WindowManager/Shell/res/values-az/strings.xml +++ b/libs/WindowManager/Shell/res/values-az/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Böyüdün"</string> <string name="minimize_button_text" msgid="271592547935841753">"Kiçildin"</string> <string name="close_button_text" msgid="2913281996024033299">"Bağlayın"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Geriyə"</string> + <string name="handle_text" msgid="1766582106752184456">"Hər kəsə açıq istifadəçi adı"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml index bd4a079f54c6..cf5394b0ebd2 100644 --- a/libs/WindowManager/Shell/res/values-be/strings.xml +++ b/libs/WindowManager/Shell/res/values-be/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Разгарнуць"</string> <string name="minimize_button_text" msgid="271592547935841753">"Згарнуць"</string> <string name="close_button_text" msgid="2913281996024033299">"Закрыць"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> + <string name="handle_text" msgid="1766582106752184456">"Маркер"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml index a04a50da7089..c525f521c0e3 100644 --- a/libs/WindowManager/Shell/res/values-bg/strings.xml +++ b/libs/WindowManager/Shell/res/values-bg/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Увеличаване"</string> <string name="minimize_button_text" msgid="271592547935841753">"Намаляване"</string> <string name="close_button_text" msgid="2913281996024033299">"Затваряне"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> + <string name="handle_text" msgid="1766582106752184456">"Манипулатор"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml index 2cc0ab321b4a..bec284d4dff8 100644 --- a/libs/WindowManager/Shell/res/values-bs/strings.xml +++ b/libs/WindowManager/Shell/res/values-bs/strings.xml @@ -84,6 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maksimiziranje"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimiziranje"</string> <string name="close_button_text" msgid="2913281996024033299">"Zatvaranje"</string> - <string name="back_button_text" msgid="1469718707134137085">"Natrag"</string> - <string name="handle_text" msgid="1766582106752184456">"Pokazivač"</string> + <string name="back_button_text" msgid="1469718707134137085">"Nazad"</string> + <string name="handle_text" msgid="1766582106752184456">"Identifikator"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml index a2badaf06989..c84bb4884068 100644 --- a/libs/WindowManager/Shell/res/values-ca/strings.xml +++ b/libs/WindowManager/Shell/res/values-ca/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maximitza"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimitza"</string> <string name="close_button_text" msgid="2913281996024033299">"Tanca"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Enrere"</string> + <string name="handle_text" msgid="1766582106752184456">"Ansa"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml index 084ea865f769..60c1f8588445 100644 --- a/libs/WindowManager/Shell/res/values-da/strings.xml +++ b/libs/WindowManager/Shell/res/values-da/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maksimér"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimer"</string> <string name="close_button_text" msgid="2913281996024033299">"Luk"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Tilbage"</string> + <string name="handle_text" msgid="1766582106752184456">"Håndtag"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml index 195c3355df2d..b57f0c857d26 100644 --- a/libs/WindowManager/Shell/res/values-de/strings.xml +++ b/libs/WindowManager/Shell/res/values-de/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maximieren"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimieren"</string> <string name="close_button_text" msgid="2913281996024033299">"Schließen"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Zurück"</string> + <string name="handle_text" msgid="1766582106752184456">"Ziehpunkt"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml index 0ad387bbd39c..aed03acf026c 100644 --- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml +++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Cerrar"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string> + <string name="handle_text" msgid="1766582106752184456">"Controlador"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml index 4b85a22a12aa..bddc2c3e61bc 100644 --- a/libs/WindowManager/Shell/res/values-es/strings.xml +++ b/libs/WindowManager/Shell/res/values-es/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Cerrar"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string> + <string name="handle_text" msgid="1766582106752184456">"Controlador"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml index cc9057815ca2..696a520d0b86 100644 --- a/libs/WindowManager/Shell/res/values-et/strings.xml +++ b/libs/WindowManager/Shell/res/values-et/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maksimeeri"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimeeri"</string> <string name="close_button_text" msgid="2913281996024033299">"Sule"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Tagasi"</string> + <string name="handle_text" msgid="1766582106752184456">"Käepide"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml index a1d0b5851f84..7550a091bd79 100644 --- a/libs/WindowManager/Shell/res/values-fa/strings.xml +++ b/libs/WindowManager/Shell/res/values-fa/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"بزرگ کردن"</string> <string name="minimize_button_text" msgid="271592547935841753">"کوچک کردن"</string> <string name="close_button_text" msgid="2913281996024033299">"بستن"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"برگشتن"</string> + <string name="handle_text" msgid="1766582106752184456">"دستگیره"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml index 5df1e04abb2a..a79adf8e686c 100644 --- a/libs/WindowManager/Shell/res/values-fi/strings.xml +++ b/libs/WindowManager/Shell/res/values-fi/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Suurenna"</string> <string name="minimize_button_text" msgid="271592547935841753">"Pienennä"</string> <string name="close_button_text" msgid="2913281996024033299">"Sulje"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Takaisin"</string> + <string name="handle_text" msgid="1766582106752184456">"Kahva"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml index c4b386aad3d1..865e2dcf4775 100644 --- a/libs/WindowManager/Shell/res/values-fr/strings.xml +++ b/libs/WindowManager/Shell/res/values-fr/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Agrandir"</string> <string name="minimize_button_text" msgid="271592547935841753">"Réduire"</string> <string name="close_button_text" msgid="2913281996024033299">"Fermer"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Retour"</string> + <string name="handle_text" msgid="1766582106752184456">"Poignée"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml index f5a106d3956d..47e6696dfe4c 100644 --- a/libs/WindowManager/Shell/res/values-gl/strings.xml +++ b/libs/WindowManager/Shell/res/values-gl/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maximizar"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizar"</string> <string name="close_button_text" msgid="2913281996024033299">"Pechar"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string> + <string name="handle_text" msgid="1766582106752184456">"Controlador"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml index 95484d5fa1d5..2c643ded9dee 100644 --- a/libs/WindowManager/Shell/res/values-hi/strings.xml +++ b/libs/WindowManager/Shell/res/values-hi/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"बड़ा करें"</string> <string name="minimize_button_text" msgid="271592547935841753">"विंडो छोटी करें"</string> <string name="close_button_text" msgid="2913281996024033299">"बंद करें"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"वापस जाएं"</string> + <string name="handle_text" msgid="1766582106752184456">"हैंडल"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml index 5ae72eb27df2..d3bca3374e9d 100644 --- a/libs/WindowManager/Shell/res/values-hy/strings.xml +++ b/libs/WindowManager/Shell/res/values-hy/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Ծավալել"</string> <string name="minimize_button_text" msgid="271592547935841753">"Ծալել"</string> <string name="close_button_text" msgid="2913281996024033299">"Փակել"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Հետ"</string> + <string name="handle_text" msgid="1766582106752184456">"Նշիչ"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml index d36a83f115ec..f157fcf6dbec 100644 --- a/libs/WindowManager/Shell/res/values-in/strings.xml +++ b/libs/WindowManager/Shell/res/values-in/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maksimalkan"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimalkan"</string> <string name="close_button_text" msgid="2913281996024033299">"Tutup"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Kembali"</string> + <string name="handle_text" msgid="1766582106752184456">"Tuas"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml index 31d483ed7c1a..ead1757ed4bb 100644 --- a/libs/WindowManager/Shell/res/values-is/strings.xml +++ b/libs/WindowManager/Shell/res/values-is/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Stækka"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minnka"</string> <string name="close_button_text" msgid="2913281996024033299">"Loka"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Til baka"</string> + <string name="handle_text" msgid="1766582106752184456">"Handfang"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml index 5c9425e92929..12c962d09ce1 100644 --- a/libs/WindowManager/Shell/res/values-iw/strings.xml +++ b/libs/WindowManager/Shell/res/values-iw/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"הגדלה"</string> <string name="minimize_button_text" msgid="271592547935841753">"מזעור"</string> <string name="close_button_text" msgid="2913281996024033299">"סגירה"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"חזרה"</string> + <string name="handle_text" msgid="1766582106752184456">"נקודת אחיזה"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml index 787ac3e1af00..b28436131fe9 100644 --- a/libs/WindowManager/Shell/res/values-ka/strings.xml +++ b/libs/WindowManager/Shell/res/values-ka/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"მაქსიმალურად გაშლა"</string> <string name="minimize_button_text" msgid="271592547935841753">"ჩაკეცვა"</string> <string name="close_button_text" msgid="2913281996024033299">"დახურვა"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"უკან"</string> + <string name="handle_text" msgid="1766582106752184456">"იდენტიფიკატორი"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml index 927f0d7a0dde..2d842b88996a 100644 --- a/libs/WindowManager/Shell/res/values-kk/strings.xml +++ b/libs/WindowManager/Shell/res/values-kk/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Жаю"</string> <string name="minimize_button_text" msgid="271592547935841753">"Кішірейту"</string> <string name="close_button_text" msgid="2913281996024033299">"Жабу"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Артқа"</string> + <string name="handle_text" msgid="1766582106752184456">"Идентификатор"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml index 955b2f88f314..3243a648ac0e 100644 --- a/libs/WindowManager/Shell/res/values-km/strings.xml +++ b/libs/WindowManager/Shell/res/values-km/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"ពង្រីក"</string> <string name="minimize_button_text" msgid="271592547935841753">"បង្រួម"</string> <string name="close_button_text" msgid="2913281996024033299">"បិទ"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"ថយក្រោយ"</string> + <string name="handle_text" msgid="1766582106752184456">"ឈ្មោះអ្នកប្រើប្រាស់"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml index a69e105876be..3a655b870df3 100644 --- a/libs/WindowManager/Shell/res/values-ko/strings.xml +++ b/libs/WindowManager/Shell/res/values-ko/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"최대화"</string> <string name="minimize_button_text" msgid="271592547935841753">"최소화"</string> <string name="close_button_text" msgid="2913281996024033299">"닫기"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"뒤로"</string> + <string name="handle_text" msgid="1766582106752184456">"핸들"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml index 15bde88c7afb..b800e3eb174f 100644 --- a/libs/WindowManager/Shell/res/values-lo/strings.xml +++ b/libs/WindowManager/Shell/res/values-lo/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"ຂະຫຍາຍໃຫຍ່ສຸດ"</string> <string name="minimize_button_text" msgid="271592547935841753">"ຫຍໍ້ລົງ"</string> <string name="close_button_text" msgid="2913281996024033299">"ປິດ"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"ກັບຄືນ"</string> + <string name="handle_text" msgid="1766582106752184456">"ມືບັງຄັບ"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml index 275efa203a74..94339a46df6f 100644 --- a/libs/WindowManager/Shell/res/values-lt/strings.xml +++ b/libs/WindowManager/Shell/res/values-lt/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Padidinti"</string> <string name="minimize_button_text" msgid="271592547935841753">"Sumažinti"</string> <string name="close_button_text" msgid="2913281996024033299">"Uždaryti"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Atgal"</string> + <string name="handle_text" msgid="1766582106752184456">"Rankenėlė"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml index 3048630e2344..d28245360922 100644 --- a/libs/WindowManager/Shell/res/values-lv/strings.xml +++ b/libs/WindowManager/Shell/res/values-lv/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maksimizēt"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizēt"</string> <string name="close_button_text" msgid="2913281996024033299">"Aizvērt"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Atpakaļ"</string> + <string name="handle_text" msgid="1766582106752184456">"Turis"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml index 9013828fb487..5db8d6d071f1 100644 --- a/libs/WindowManager/Shell/res/values-ml/strings.xml +++ b/libs/WindowManager/Shell/res/values-ml/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"വലുതാക്കുക"</string> <string name="minimize_button_text" msgid="271592547935841753">"ചെറുതാക്കുക"</string> <string name="close_button_text" msgid="2913281996024033299">"അടയ്ക്കുക"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"മടങ്ങുക"</string> + <string name="handle_text" msgid="1766582106752184456">"ഹാൻഡിൽ"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml index dc884e9bf3dd..779cf5c870bc 100644 --- a/libs/WindowManager/Shell/res/values-mr/strings.xml +++ b/libs/WindowManager/Shell/res/values-mr/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"मोठे करा"</string> <string name="minimize_button_text" msgid="271592547935841753">"लहान करा"</string> <string name="close_button_text" msgid="2913281996024033299">"बंद करा"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"मागे जा"</string> + <string name="handle_text" msgid="1766582106752184456">"हँडल"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml index a2f24f2c948b..0ceee2d1c928 100644 --- a/libs/WindowManager/Shell/res/values-nb/strings.xml +++ b/libs/WindowManager/Shell/res/values-nb/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maksimer"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimer"</string> <string name="close_button_text" msgid="2913281996024033299">"Lukk"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Tilbake"</string> + <string name="handle_text" msgid="1766582106752184456">"Håndtak"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml index 6a70d8da05ed..7ba49e57111e 100644 --- a/libs/WindowManager/Shell/res/values-ne/strings.xml +++ b/libs/WindowManager/Shell/res/values-ne/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"ठुलो बनाउनुहोस्"</string> <string name="minimize_button_text" msgid="271592547935841753">"मिनिमाइज गर्नुहोस्"</string> <string name="close_button_text" msgid="2913281996024033299">"बन्द गर्नुहोस्"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"पछाडि"</string> + <string name="handle_text" msgid="1766582106752184456">"ह्यान्डल"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml index d1d7db80caf5..dd3ebe415218 100644 --- a/libs/WindowManager/Shell/res/values-nl/strings.xml +++ b/libs/WindowManager/Shell/res/values-nl/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maximaliseren"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimaliseren"</string> <string name="close_button_text" msgid="2913281996024033299">"Sluiten"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Terug"</string> + <string name="handle_text" msgid="1766582106752184456">"Gebruikersnaam"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml index d2a96d95db74..c3056ca0a511 100644 --- a/libs/WindowManager/Shell/res/values-pa/strings.xml +++ b/libs/WindowManager/Shell/res/values-pa/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"ਵੱਡਾ ਕਰੋ"</string> <string name="minimize_button_text" msgid="271592547935841753">"ਛੋਟਾ ਕਰੋ"</string> <string name="close_button_text" msgid="2913281996024033299">"ਬੰਦ ਕਰੋ"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"ਪਿੱਛੇ"</string> + <string name="handle_text" msgid="1766582106752184456">"ਹੈਂਡਲ"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml index cc2b2c314a85..56a6fb1664c1 100644 --- a/libs/WindowManager/Shell/res/values-pl/strings.xml +++ b/libs/WindowManager/Shell/res/values-pl/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maksymalizuj"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimalizuj"</string> <string name="close_button_text" msgid="2913281996024033299">"Zamknij"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Wstecz"</string> + <string name="handle_text" msgid="1766582106752184456">"Uchwyt"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml index 98a775e1e6b3..b96caf23a0a7 100644 --- a/libs/WindowManager/Shell/res/values-ru/strings.xml +++ b/libs/WindowManager/Shell/res/values-ru/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Развернуть"</string> <string name="minimize_button_text" msgid="271592547935841753">"Свернуть"</string> <string name="close_button_text" msgid="2913281996024033299">"Закрыть"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> + <string name="handle_text" msgid="1766582106752184456">"Маркер"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml index 57240618ef19..a1ec3b5d5bb2 100644 --- a/libs/WindowManager/Shell/res/values-si/strings.xml +++ b/libs/WindowManager/Shell/res/values-si/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"විහිදන්න"</string> <string name="minimize_button_text" msgid="271592547935841753">"කුඩා කරන්න"</string> <string name="close_button_text" msgid="2913281996024033299">"වසන්න"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"ආපසු"</string> + <string name="handle_text" msgid="1766582106752184456">"හැඬලය"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml index 12f022e7a1f6..2f995e5076f3 100644 --- a/libs/WindowManager/Shell/res/values-sl/strings.xml +++ b/libs/WindowManager/Shell/res/values-sl/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maksimiraj"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimiraj"</string> <string name="close_button_text" msgid="2913281996024033299">"Zapri"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Nazaj"</string> + <string name="handle_text" msgid="1766582106752184456">"Ročica"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml index cdd870689886..3d9bde4f8066 100644 --- a/libs/WindowManager/Shell/res/values-sq/strings.xml +++ b/libs/WindowManager/Shell/res/values-sq/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Maksimizo"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimizo"</string> <string name="close_button_text" msgid="2913281996024033299">"Mbyll"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Pas"</string> + <string name="handle_text" msgid="1766582106752184456">"Emërtimi"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml index fef3792b35a2..b39fd04ebf3d 100644 --- a/libs/WindowManager/Shell/res/values-sv/strings.xml +++ b/libs/WindowManager/Shell/res/values-sv/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Utöka"</string> <string name="minimize_button_text" msgid="271592547935841753">"Minimera"</string> <string name="close_button_text" msgid="2913281996024033299">"Stäng"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Tillbaka"</string> + <string name="handle_text" msgid="1766582106752184456">"Handtag"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml index 2d10e2039a11..f4d4ceec5a1f 100644 --- a/libs/WindowManager/Shell/res/values-sw/strings.xml +++ b/libs/WindowManager/Shell/res/values-sw/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Panua"</string> <string name="minimize_button_text" msgid="271592547935841753">"Punguza"</string> <string name="close_button_text" msgid="2913281996024033299">"Funga"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Rudi nyuma"</string> + <string name="handle_text" msgid="1766582106752184456">"Ncha"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml index 0eeeca78cb86..6d050c2ba26e 100644 --- a/libs/WindowManager/Shell/res/values-ta/strings.xml +++ b/libs/WindowManager/Shell/res/values-ta/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"பெரிதாக்கும்"</string> <string name="minimize_button_text" msgid="271592547935841753">"சிறிதாக்கும்"</string> <string name="close_button_text" msgid="2913281996024033299">"மூடும்"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"பின்செல்லும்"</string> + <string name="handle_text" msgid="1766582106752184456">"ஹேண்டில்"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml index 2b105bdb7963..025e2e6215e7 100644 --- a/libs/WindowManager/Shell/res/values-tr/strings.xml +++ b/libs/WindowManager/Shell/res/values-tr/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Ekranı Kapla"</string> <string name="minimize_button_text" msgid="271592547935841753">"Küçült"</string> <string name="close_button_text" msgid="2913281996024033299">"Kapat"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Geri"</string> + <string name="handle_text" msgid="1766582106752184456">"Herkese açık kullanıcı adı"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml index a0925318ac26..97bb68080117 100644 --- a/libs/WindowManager/Shell/res/values-uk/strings.xml +++ b/libs/WindowManager/Shell/res/values-uk/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Збільшити"</string> <string name="minimize_button_text" msgid="271592547935841753">"Згорнути"</string> <string name="close_button_text" msgid="2913281996024033299">"Закрити"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Назад"</string> + <string name="handle_text" msgid="1766582106752184456">"Маркер"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml index 0330125c3e6f..ce73bd586c71 100644 --- a/libs/WindowManager/Shell/res/values-uz/strings.xml +++ b/libs/WindowManager/Shell/res/values-uz/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Yoyish"</string> <string name="minimize_button_text" msgid="271592547935841753">"Kichraytirish"</string> <string name="close_button_text" msgid="2913281996024033299">"Yopish"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Orqaga"</string> + <string name="handle_text" msgid="1766582106752184456">"Identifikator"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml index 6e4a7682854d..511db6fbc116 100644 --- a/libs/WindowManager/Shell/res/values-vi/strings.xml +++ b/libs/WindowManager/Shell/res/values-vi/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"Phóng to"</string> <string name="minimize_button_text" msgid="271592547935841753">"Thu nhỏ"</string> <string name="close_button_text" msgid="2913281996024033299">"Đóng"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"Quay lại"</string> + <string name="handle_text" msgid="1766582106752184456">"Xử lý"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml index df911ed55ab3..16cbf126eff8 100644 --- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml +++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml @@ -84,8 +84,6 @@ <string name="maximize_button_text" msgid="1650859196290301963">"最大化"</string> <string name="minimize_button_text" msgid="271592547935841753">"最小化"</string> <string name="close_button_text" msgid="2913281996024033299">"关闭"</string> - <!-- no translation found for back_button_text (1469718707134137085) --> - <skip /> - <!-- no translation found for handle_text (1766582106752184456) --> - <skip /> + <string name="back_button_text" msgid="1469718707134137085">"返回"</string> + <string name="handle_text" msgid="1766582106752184456">"处理"</string> </resources> diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml index f48402264a73..59d87a0a9371 100644 --- a/libs/WindowManager/Shell/res/values-zu/strings.xml +++ b/libs/WindowManager/Shell/res/values-zu/strings.xml @@ -19,7 +19,7 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <string name="pip_phone_close" msgid="5783752637260411309">"Vala"</string> <string name="pip_phone_expand" msgid="2579292903468287504">"Nweba"</string> - <string name="pip_phone_settings" msgid="5468987116750491918">"Izilungiselelo"</string> + <string name="pip_phone_settings" msgid="5468987116750491918">"Amasethingi"</string> <string name="pip_phone_enter_split" msgid="7042877263880641911">"Faka ukuhlukanisa isikrini"</string> <string name="pip_menu_title" msgid="5393619322111827096">"Imenyu"</string> <string name="pip_notification_title" msgid="1347104727641353453">"U-<xliff:g id="NAME">%s</xliff:g> ungaphakathi kwesithombe esiphakathi kwesithombe"</string> diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java index e90389764af3..f209521b1da4 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/SplitBounds.java @@ -33,6 +33,8 @@ public class SplitBounds implements Parcelable { // This class is orientation-agnostic, so we compute both for later use public final float topTaskPercent; public final float leftTaskPercent; + public final float dividerWidthPercent; + public final float dividerHeightPercent; /** * If {@code true}, that means at the time of creation of this object, the * split-screened apps were vertically stacked. This is useful in scenarios like @@ -62,8 +64,12 @@ public class SplitBounds implements Parcelable { appsStackedVertically = false; } - leftTaskPercent = this.leftTopBounds.width() / (float) rightBottomBounds.right; - topTaskPercent = this.leftTopBounds.height() / (float) rightBottomBounds.bottom; + float totalWidth = rightBottomBounds.right - leftTopBounds.left; + float totalHeight = rightBottomBounds.bottom - leftTopBounds.top; + leftTaskPercent = leftTopBounds.width() / totalWidth; + topTaskPercent = leftTopBounds.height() / totalHeight; + dividerWidthPercent = visualDividerBounds.width() / totalWidth; + dividerHeightPercent = visualDividerBounds.height() / totalHeight; } public SplitBounds(Parcel parcel) { @@ -75,6 +81,8 @@ public class SplitBounds implements Parcelable { appsStackedVertically = parcel.readBoolean(); leftTopTaskId = parcel.readInt(); rightBottomTaskId = parcel.readInt(); + dividerWidthPercent = parcel.readInt(); + dividerHeightPercent = parcel.readInt(); } @Override @@ -87,6 +95,8 @@ public class SplitBounds implements Parcelable { parcel.writeBoolean(appsStackedVertically); parcel.writeInt(leftTopTaskId); parcel.writeInt(rightBottomTaskId); + parcel.writeFloat(dividerWidthPercent); + parcel.writeFloat(dividerHeightPercent); } @Override diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml index 18b8ca9b4dd6..77dfbeee9bbf 100644 --- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml +++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml @@ -16,7 +16,7 @@ <resources xmlns:android="http://schemas.android.com/apk/res/android" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <string name="app_label" msgid="4470785958457506021">"隨附裝置管理員"</string> + <string name="app_label" msgid="4470785958457506021">"隨附裝置管理工具"</string> <string name="confirmation_title" msgid="3785000297483688997">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」<strong></strong>存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」<strong></strong>"</string> <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string> <string name="chooser_title" msgid="2262294130493605839">"選擇要讓「<xliff:g id="APP_NAME">%2$s</xliff:g>」<strong></strong>管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string> diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt index ca36fa43da76..fdfad2bc2fa1 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt @@ -25,7 +25,6 @@ import android.graphics.Rect import android.os.Looper import android.util.Log import android.util.MathUtils -import android.view.GhostView import android.view.View import android.view.ViewGroup import android.view.ViewGroup.LayoutParams.MATCH_PARENT @@ -86,6 +85,9 @@ constructor( */ val sourceIdentity: Any + /** The CUJ associated to this controller. */ + val cuj: DialogCuj? + /** * Move the drawing of the source in the overlay of [viewGroup]. * @@ -142,7 +144,31 @@ constructor( * controlled by this controller. */ // TODO(b/252723237): Make this non-nullable - fun jankConfigurationBuilder(cuj: Int): InteractionJankMonitor.Configuration.Builder? + fun jankConfigurationBuilder(): InteractionJankMonitor.Configuration.Builder? + + companion object { + /** + * Create a [Controller] that can animate [source] to and from a dialog. + * + * Important: The view must be attached to a [ViewGroup] when calling this function and + * during the animation. For safety, this method will return null when it is not. + * + * Note: The background of [view] should be a (rounded) rectangle so that it can be + * properly animated. + */ + fun fromView(source: View, cuj: DialogCuj? = null): Controller? { + if (source.parent !is ViewGroup) { + Log.e( + TAG, + "Skipping animation as view $source is not attached to a ViewGroup", + Exception(), + ) + return null + } + + return ViewDialogLaunchAnimatorController(source, cuj) + } + } } /** @@ -172,7 +198,12 @@ constructor( cuj: DialogCuj? = null, animateBackgroundBoundsChange: Boolean = false ) { - show(dialog, createController(view), cuj, animateBackgroundBoundsChange) + val controller = Controller.fromView(view, cuj) + if (controller == null) { + dialog.show() + } else { + show(dialog, controller, animateBackgroundBoundsChange) + } } /** @@ -187,10 +218,10 @@ constructor( * Caveats: When calling this function and [dialog] is not a fullscreen dialog, then it will be * made fullscreen and 2 views will be inserted between the dialog DecorView and its children. */ + @JvmOverloads fun show( dialog: Dialog, controller: Controller, - cuj: DialogCuj? = null, animateBackgroundBoundsChange: Boolean = false ) { if (Looper.myLooper() != Looper.getMainLooper()) { @@ -207,7 +238,10 @@ constructor( it.dialog.window.decorView.viewRootImpl == controller.viewRoot } val animateFrom = - animatedParent?.dialogContentWithBackground?.let { createController(it) } ?: controller + animatedParent?.dialogContentWithBackground?.let { + Controller.fromView(it, controller.cuj) + } + ?: controller if (animatedParent == null && animateFrom !is LaunchableView) { // Make sure the View we launch from implements LaunchableView to avoid visibility @@ -244,96 +278,12 @@ constructor( animateBackgroundBoundsChange, animatedParent, isForTesting, - cuj, ) openedDialogs.add(animatedDialog) animatedDialog.start() } - /** Create a [Controller] that can animate [source] to & from a dialog. */ - private fun createController(source: View): Controller { - return object : Controller { - override val viewRoot: ViewRootImpl - get() = source.viewRootImpl - - override val sourceIdentity: Any = source - - override fun startDrawingInOverlayOf(viewGroup: ViewGroup) { - // Create a temporary ghost of the source (which will make it invisible) and add it - // to the host dialog. - GhostView.addGhost(source, viewGroup) - - // The ghost of the source was just created, so the source is currently invisible. - // We need to make sure that it stays invisible as long as the dialog is shown or - // animating. - (source as? LaunchableView)?.setShouldBlockVisibilityChanges(true) - } - - override fun stopDrawingInOverlay() { - // Note: here we should remove the ghost from the overlay, but in practice this is - // already done by the launch controllers created below. - - // Make sure we allow the source to change its visibility again. - (source as? LaunchableView)?.setShouldBlockVisibilityChanges(false) - source.visibility = View.VISIBLE - } - - override fun createLaunchController(): LaunchAnimator.Controller { - val delegate = GhostedViewLaunchAnimatorController(source) - return object : LaunchAnimator.Controller by delegate { - override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { - // Remove the temporary ghost added by [startDrawingInOverlayOf]. Another - // ghost (that ghosts only the source content, and not its background) will - // be added right after this by the delegate and will be animated. - GhostView.removeGhost(source) - delegate.onLaunchAnimationStart(isExpandingFullyAbove) - } - - override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { - delegate.onLaunchAnimationEnd(isExpandingFullyAbove) - - // We hide the source when the dialog is showing. We will make this view - // visible again when dismissing the dialog. This does nothing if the source - // implements [LaunchableView], as it's already INVISIBLE in that case. - source.visibility = View.INVISIBLE - } - } - } - - override fun createExitController(): LaunchAnimator.Controller { - return GhostedViewLaunchAnimatorController(source) - } - - override fun shouldAnimateExit(): Boolean { - // The source should be invisible by now, if it's not then something else changed - // its visibility and we probably don't want to run the animation. - if (source.visibility != View.INVISIBLE) { - return false - } - - return source.isAttachedToWindow && ((source.parent as? View)?.isShown ?: true) - } - - override fun onExitAnimationCancelled() { - // Make sure we allow the source to change its visibility again. - (source as? LaunchableView)?.setShouldBlockVisibilityChanges(false) - - // If the view is invisible it's probably because of us, so we make it visible - // again. - if (source.visibility == View.INVISIBLE) { - source.visibility = View.VISIBLE - } - } - - override fun jankConfigurationBuilder( - cuj: Int - ): InteractionJankMonitor.Configuration.Builder? { - return InteractionJankMonitor.Configuration.Builder.withView(cuj, source) - } - } - } - /** * Launch [dialog] from [another dialog][animateFrom] that was shown using [show]. This will * allow for dismissing the whole stack. @@ -563,9 +513,6 @@ private class AnimatedDialog( * Whether synchronization should be disabled, which can be useful if we are running in a test. */ private val forceDisableSynchronization: Boolean, - - /** Interaction to which the dialog animation is associated. */ - private val cuj: DialogCuj? = null ) { /** * The DecorView of this dialog window. @@ -618,8 +565,9 @@ private class AnimatedDialog( private var hasInstrumentedJank = false fun start() { + val cuj = controller.cuj if (cuj != null) { - val config = controller.jankConfigurationBuilder(cuj.cujType) + val config = controller.jankConfigurationBuilder() if (config != null) { if (cuj.tag != null) { config.setTag(cuj.tag) @@ -917,7 +865,7 @@ private class AnimatedDialog( } if (hasInstrumentedJank) { - interactionJankMonitor.end(cuj!!.cujType) + interactionJankMonitor.end(controller.cuj!!.cujType) } } ) diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt index 8ce372dbb278..40a5e9794d37 100644 --- a/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Expandable.kt @@ -30,7 +30,12 @@ interface Expandable { */ fun activityLaunchController(cujType: Int? = null): ActivityLaunchAnimator.Controller? - // TODO(b/230830644): Introduce DialogLaunchAnimator and a function to expose it here. + /** + * Create a [DialogLaunchAnimator.Controller] that can be used to expand this [Expandable] into + * a Dialog, or return `null` if this [Expandable] should not be animated (e.g. if it is + * currently not attached or visible). + */ + fun dialogLaunchController(cuj: DialogCuj? = null): DialogLaunchAnimator.Controller? companion object { /** @@ -39,6 +44,7 @@ interface Expandable { * Note: The background of [view] should be a (rounded) rectangle so that it can be properly * animated. */ + @JvmStatic fun fromView(view: View): Expandable { return object : Expandable { override fun activityLaunchController( @@ -46,6 +52,12 @@ interface Expandable { ): ActivityLaunchAnimator.Controller? { return ActivityLaunchAnimator.Controller.fromView(view, cujType) } + + override fun dialogLaunchController( + cuj: DialogCuj? + ): DialogLaunchAnimator.Controller? { + return DialogLaunchAnimator.Controller.fromView(view, cuj) + } } } } diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt new file mode 100644 index 000000000000..ecee598afe4e --- /dev/null +++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt @@ -0,0 +1,107 @@ +/* + * 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.systemui.animation + +import android.view.GhostView +import android.view.View +import android.view.ViewGroup +import android.view.ViewRootImpl +import com.android.internal.jank.InteractionJankMonitor + +/** A [DialogLaunchAnimator.Controller] that can animate a [View] from/to a dialog. */ +class ViewDialogLaunchAnimatorController +internal constructor( + private val source: View, + override val cuj: DialogCuj?, +) : DialogLaunchAnimator.Controller { + override val viewRoot: ViewRootImpl + get() = source.viewRootImpl + + override val sourceIdentity: Any = source + + override fun startDrawingInOverlayOf(viewGroup: ViewGroup) { + // Create a temporary ghost of the source (which will make it invisible) and add it + // to the host dialog. + GhostView.addGhost(source, viewGroup) + + // The ghost of the source was just created, so the source is currently invisible. + // We need to make sure that it stays invisible as long as the dialog is shown or + // animating. + (source as? LaunchableView)?.setShouldBlockVisibilityChanges(true) + } + + override fun stopDrawingInOverlay() { + // Note: here we should remove the ghost from the overlay, but in practice this is + // already done by the launch controllers created below. + + // Make sure we allow the source to change its visibility again. + (source as? LaunchableView)?.setShouldBlockVisibilityChanges(false) + source.visibility = View.VISIBLE + } + + override fun createLaunchController(): LaunchAnimator.Controller { + val delegate = GhostedViewLaunchAnimatorController(source) + return object : LaunchAnimator.Controller by delegate { + override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { + // Remove the temporary ghost added by [startDrawingInOverlayOf]. Another + // ghost (that ghosts only the source content, and not its background) will + // be added right after this by the delegate and will be animated. + GhostView.removeGhost(source) + delegate.onLaunchAnimationStart(isExpandingFullyAbove) + } + + override fun onLaunchAnimationEnd(isExpandingFullyAbove: Boolean) { + delegate.onLaunchAnimationEnd(isExpandingFullyAbove) + + // We hide the source when the dialog is showing. We will make this view + // visible again when dismissing the dialog. This does nothing if the source + // implements [LaunchableView], as it's already INVISIBLE in that case. + source.visibility = View.INVISIBLE + } + } + } + + override fun createExitController(): LaunchAnimator.Controller { + return GhostedViewLaunchAnimatorController(source) + } + + override fun shouldAnimateExit(): Boolean { + // The source should be invisible by now, if it's not then something else changed + // its visibility and we probably don't want to run the animation. + if (source.visibility != View.INVISIBLE) { + return false + } + + return source.isAttachedToWindow && ((source.parent as? View)?.isShown ?: true) + } + + override fun onExitAnimationCancelled() { + // Make sure we allow the source to change its visibility again. + (source as? LaunchableView)?.setShouldBlockVisibilityChanges(false) + + // If the view is invisible it's probably because of us, so we make it visible + // again. + if (source.visibility == View.INVISIBLE) { + source.visibility = View.VISIBLE + } + } + + override fun jankConfigurationBuilder(): InteractionJankMonitor.Configuration.Builder? { + val type = cuj?.cujType ?: return null + return InteractionJankMonitor.Configuration.Builder.withView(type, source) + } +} diff --git a/packages/SystemUI/checks/Android.bp b/packages/SystemUI/checks/Android.bp index 8457312dc403..cf66ff60f9ab 100644 --- a/packages/SystemUI/checks/Android.bp +++ b/packages/SystemUI/checks/Android.bp @@ -40,6 +40,10 @@ java_test_host { "tests/**/*.kt", "tests/**/*.java", ], + data: [ + ":framework", + ":androidx.annotation_annotation", + ], static_libs: [ "SystemUILintChecker", "junit", diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SoftwareBitmapDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SoftwareBitmapDetector.kt index 4eeeb850292a..4b9aa13c0240 100644 --- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SoftwareBitmapDetector.kt +++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SoftwareBitmapDetector.kt @@ -32,7 +32,8 @@ import org.jetbrains.uast.UReferenceExpression class SoftwareBitmapDetector : Detector(), SourceCodeScanner { override fun getApplicableReferenceNames(): List<String> { - return mutableListOf("ALPHA_8", "RGB_565", "ARGB_8888", "RGBA_F16", "RGBA_1010102") + return mutableListOf( + "ALPHA_8", "RGB_565", "ARGB_4444", "ARGB_8888", "RGBA_F16", "RGBA_1010102") } override fun visitReference( @@ -40,13 +41,12 @@ class SoftwareBitmapDetector : Detector(), SourceCodeScanner { reference: UReferenceExpression, referenced: PsiElement ) { - val evaluator = context.evaluator if (evaluator.isMemberInClass(referenced as? PsiField, "android.graphics.Bitmap.Config")) { context.report( ISSUE, referenced, - context.getNameLocation(referenced), + context.getNameLocation(reference), "Replace software bitmap with `Config.HARDWARE`" ) } diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/AndroidStubs.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/AndroidStubs.kt index d4c55c0d9149..141dd0535986 100644 --- a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/AndroidStubs.kt +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/AndroidStubs.kt @@ -18,185 +18,22 @@ package com.android.internal.systemui.lint import com.android.annotations.NonNull import com.android.tools.lint.checks.infrastructure.LintDetectorTest.java +import com.android.tools.lint.checks.infrastructure.TestFiles.LibraryReferenceTestFile +import java.io.File import org.intellij.lang.annotations.Language @Suppress("UnstableApiUsage") @NonNull private fun indentedJava(@NonNull @Language("JAVA") source: String) = java(source).indented() -internal val commonSettingsCode = - """ -public static float getFloat(ContentResolver cr, String name) { return 0.0f; } -public static long getLong(ContentResolver cr, String name) { - return 0L; -} -public static int getInt(ContentResolver cr, String name) { - return 0; -} -public static String getString(ContentResolver cr, String name) { - return ""; -} -public static float getFloat(ContentResolver cr, String name, float def) { - return 0.0f; -} -public static long getLong(ContentResolver cr, String name, long def) { - return 0L; -} -public static int getInt(ContentResolver cr, String name, int def) { - return 0; -} -public static String getString(ContentResolver cr, String name, String def) { - return ""; -} -public static boolean putFloat(ContentResolver cr, String name, float value) { - return true; -} -public static boolean putLong(ContentResolver cr, String name, long value) { - return true; -} -public static boolean putInt(ContentResolver cr, String name, int value) { - return true; -} -public static boolean putFloat(ContentResolver cr, String name) { - return true; -} -public static boolean putString(ContentResolver cr, String name, String value) { - return true; -} -""" - /* * This file contains stubs of framework APIs and System UI classes for testing purposes only. The * stubs are not used in the lint detectors themselves. */ internal val androidStubs = arrayOf( - indentedJava( - """ -package android.app; - -public class ActivityManager { - public static int getCurrentUser() {} -} -""" - ), - indentedJava( - """ -package android.accounts; - -public class AccountManager { - public static AccountManager get(Context context) { return null; } -} -""" - ), - indentedJava( - """ -package android.os; -import android.content.pm.UserInfo; -import android.annotation.UserIdInt; - -public class UserManager { - public UserInfo getUserInfo(@UserIdInt int userId) {} -} -""" - ), - indentedJava(""" -package android.annotation; - -public @interface UserIdInt {} -"""), - indentedJava(""" -package android.content.pm; - -public class UserInfo {} -"""), - indentedJava(""" -package android.os; - -public class Looper {} -"""), - indentedJava(""" -package android.os; - -public class Handler {} -"""), - indentedJava(""" -package android.content; - -public class ServiceConnection {} -"""), - indentedJava(""" -package android.os; - -public enum UserHandle { - ALL -} -"""), - indentedJava( - """ -package android.content; -import android.os.UserHandle; -import android.os.Handler; -import android.os.Looper; -import java.util.concurrent.Executor; - -public class Context { - public void registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) {} - public void registerReceiverAsUser( - BroadcastReceiver receiver, UserHandle user, IntentFilter filter, - String broadcastPermission, Handler scheduler) {} - public void registerReceiverForAllUsers( - BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, - Handler scheduler) {} - public void sendBroadcast(Intent intent) {} - public void sendBroadcast(Intent intent, String receiverPermission) {} - public void sendBroadcastAsUser(Intent intent, UserHandle userHandle, String permission) {} - public void bindService(Intent intent) {} - public void bindServiceAsUser( - Intent intent, ServiceConnection connection, int flags, UserHandle userHandle) {} - public void unbindService(ServiceConnection connection) {} - public Looper getMainLooper() { return null; } - public Executor getMainExecutor() { return null; } - public Handler getMainThreadHandler() { return null; } - public final @Nullable <T> T getSystemService(@NonNull Class<T> serviceClass) { return null; } - public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name); -} -""" - ), - indentedJava( - """ -package android.app; -import android.content.Context; - -public class Activity extends Context {} -""" - ), - indentedJava( - """ -package android.graphics; - -public class Bitmap { - public enum Config { - ARGB_8888, - RGB_565, - HARDWARE - } - public static Bitmap createBitmap(int width, int height, Config config) { - return null; - } -} -""" - ), - indentedJava(""" -package android.content; - -public class BroadcastReceiver {} -"""), - indentedJava(""" -package android.content; - -public class IntentFilter {} -"""), + LibraryReferenceTestFile(File("framework.jar").canonicalFile), + LibraryReferenceTestFile(File("androidx.annotation_annotation.jar").canonicalFile), indentedJava( """ package com.android.systemui.settings; @@ -208,47 +45,4 @@ public interface UserTracker { } """ ), - indentedJava( - """ -package androidx.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.CONSTRUCTOR; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.SOURCE; - -@Retention(SOURCE) -@Target({METHOD,CONSTRUCTOR,TYPE,PARAMETER}) -public @interface WorkerThread { -} -""" - ), - indentedJava( - """ -package android.provider; - -public class Settings { - public static final class Global { - public static final String UNLOCK_SOUND = "unlock_sound"; - """ + - commonSettingsCode + - """ - } - public static final class Secure { - """ + - commonSettingsCode + - """ - } - public static final class System { - """ + - commonSettingsCode + - """ - } -} -""" - ), ) diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SoftwareBitmapDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SoftwareBitmapDetectorTest.kt index 090ddf88fa3c..c632636eb9c8 100644 --- a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SoftwareBitmapDetectorTest.kt +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SoftwareBitmapDetectorTest.kt @@ -51,12 +51,12 @@ class SoftwareBitmapDetectorTest : SystemUILintDetectorTest() { .run() .expect( """ - src/android/graphics/Bitmap.java:5: Warning: Replace software bitmap with Config.HARDWARE [SoftwareBitmap] - ARGB_8888, - ~~~~~~~~~ - src/android/graphics/Bitmap.java:6: Warning: Replace software bitmap with Config.HARDWARE [SoftwareBitmap] - RGB_565, - ~~~~~~~ + src/TestClass.java:5: Warning: Replace software bitmap with Config.HARDWARE [SoftwareBitmap] + Bitmap.createBitmap(300, 300, Bitmap.Config.RGB_565); + ~~~~~~~ + src/TestClass.java:6: Warning: Replace software bitmap with Config.HARDWARE [SoftwareBitmap] + Bitmap.createBitmap(300, 300, Bitmap.Config.ARGB_8888); + ~~~~~~~~~ 0 errors, 2 warnings """ ) @@ -67,7 +67,7 @@ class SoftwareBitmapDetectorTest : SystemUILintDetectorTest() { lint() .files( TestFiles.java( - """ + """ import android.graphics.Bitmap; public class TestClass { @@ -76,8 +76,7 @@ class SoftwareBitmapDetectorTest : SystemUILintDetectorTest() { } } """ - ) - .indented(), + ), *stubs ) .issues(SoftwareBitmapDetector.ISSUE) diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SystemUILintDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SystemUILintDetectorTest.kt index 2183b3805eed..3f93f075fe8b 100644 --- a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SystemUILintDetectorTest.kt +++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/SystemUILintDetectorTest.kt @@ -3,9 +3,42 @@ package com.android.internal.systemui.lint import com.android.tools.lint.checks.infrastructure.LintDetectorTest import com.android.tools.lint.checks.infrastructure.TestLintTask import java.io.File +import org.junit.ClassRule +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.runners.model.Statement @Suppress("UnstableApiUsage") +@RunWith(JUnit4::class) abstract class SystemUILintDetectorTest : LintDetectorTest() { + + companion object { + @ClassRule + @JvmField + val libraryChecker: LibraryExists = + LibraryExists("framework.jar", "androidx.annotation_annotation.jar") + } + + class LibraryExists(vararg val libraryNames: String) : TestRule { + override fun apply(base: Statement, description: Description): Statement { + return object : Statement() { + override fun evaluate() { + for (libName in libraryNames) { + val libFile = File(libName) + if (!libFile.canonicalFile.exists()) { + throw Exception( + "Could not find $libName in the test's working directory. " + + "File ${libFile.absolutePath} does not exist." + ) + } + } + base.evaluate() + } + } + } + } /** * Customize the lint task to disable SDK usage completely. This ensures that running the tests * in Android Studio has the same result as running the tests in atest diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/animation/ExpandableController.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/animation/ExpandableController.kt index 065c3149c2f5..50c3d7e1e76b 100644 --- a/packages/SystemUI/compose/core/src/com/android/systemui/compose/animation/ExpandableController.kt +++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/animation/ExpandableController.kt @@ -40,17 +40,16 @@ import androidx.compose.ui.unit.Density import androidx.compose.ui.unit.LayoutDirection import com.android.internal.jank.InteractionJankMonitor import com.android.systemui.animation.ActivityLaunchAnimator +import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogLaunchAnimator +import com.android.systemui.animation.Expandable import com.android.systemui.animation.LaunchAnimator import kotlin.math.roundToInt -/** A controller that can control animated launches. */ +/** A controller that can control animated launches from an [Expandable]. */ interface ExpandableController { - /** Create an [ActivityLaunchAnimator.Controller] to animate into an Activity. */ - fun forActivity(): ActivityLaunchAnimator.Controller - - /** Create a [DialogLaunchAnimator.Controller] to animate into a Dialog. */ - fun forDialog(): DialogLaunchAnimator.Controller + /** The [Expandable] controlled by this controller. */ + val expandable: Expandable } /** @@ -120,13 +119,26 @@ internal class ExpandableControllerImpl( private val layoutDirection: LayoutDirection, private val isComposed: State<Boolean>, ) : ExpandableController { - override fun forActivity(): ActivityLaunchAnimator.Controller { - return activityController() - } + override val expandable: Expandable = + object : Expandable { + override fun activityLaunchController( + cujType: Int?, + ): ActivityLaunchAnimator.Controller? { + if (!isComposed.value) { + return null + } - override fun forDialog(): DialogLaunchAnimator.Controller { - return dialogController() - } + return activityController(cujType) + } + + override fun dialogLaunchController(cuj: DialogCuj?): DialogLaunchAnimator.Controller? { + if (!isComposed.value) { + return null + } + + return dialogController(cuj) + } + } /** * Create a [LaunchAnimator.Controller] that is going to be used to drive an activity or dialog @@ -233,7 +245,7 @@ internal class ExpandableControllerImpl( } /** Create an [ActivityLaunchAnimator.Controller] that can be used to animate activities. */ - private fun activityController(): ActivityLaunchAnimator.Controller { + private fun activityController(cujType: Int?): ActivityLaunchAnimator.Controller { val delegate = launchController() return object : ActivityLaunchAnimator.Controller, LaunchAnimator.Controller by delegate { override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) { @@ -248,10 +260,11 @@ internal class ExpandableControllerImpl( } } - private fun dialogController(): DialogLaunchAnimator.Controller { + private fun dialogController(cuj: DialogCuj?): DialogLaunchAnimator.Controller { return object : DialogLaunchAnimator.Controller { override val viewRoot: ViewRootImpl = composeViewRoot.viewRootImpl override val sourceIdentity: Any = this@ExpandableControllerImpl + override val cuj: DialogCuj? = cuj override fun startDrawingInOverlayOf(viewGroup: ViewGroup) { val newOverlay = viewGroup.overlay as ViewGroupOverlay @@ -294,9 +307,7 @@ internal class ExpandableControllerImpl( isDialogShowing.value = false } - override fun jankConfigurationBuilder( - cuj: Int - ): InteractionJankMonitor.Configuration.Builder? { + override fun jankConfigurationBuilder(): InteractionJankMonitor.Configuration.Builder? { // TODO(b/252723237): Add support for jank monitoring when animating from a // Composable. return null diff --git a/packages/SystemUI/res/drawable-hdpi/textfield_default_filled.9.png b/packages/SystemUI/res/drawable-hdpi/textfield_default_filled.9.png Binary files differnew file mode 100644 index 000000000000..3dd997fade6c --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/textfield_default_filled.9.png diff --git a/packages/SystemUI/res/drawable-mdpi/textfield_default_filled.9.png b/packages/SystemUI/res/drawable-mdpi/textfield_default_filled.9.png Binary files differnew file mode 100644 index 000000000000..80aba01091fe --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/textfield_default_filled.9.png diff --git a/packages/SystemUI/res/drawable-xhdpi/textfield_default_filled.9.png b/packages/SystemUI/res/drawable-xhdpi/textfield_default_filled.9.png Binary files differnew file mode 100644 index 000000000000..b3f89ed7ea7a --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/textfield_default_filled.9.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/textfield_default_filled.9.png b/packages/SystemUI/res/drawable-xxhdpi/textfield_default_filled.9.png Binary files differnew file mode 100644 index 000000000000..efa2cb988ac1 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/textfield_default_filled.9.png diff --git a/packages/SystemUI/res/drawable/edit_text_filled.xml b/packages/SystemUI/res/drawable/edit_text_filled.xml new file mode 100644 index 000000000000..cca34d456078 --- /dev/null +++ b/packages/SystemUI/res/drawable/edit_text_filled.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:insetLeft="4dp" + android:insetRight="4dp" + android:insetTop="10dp" + android:insetBottom="10dp"> + <selector> + <item android:state_enabled="false"> + <nine-patch android:src="@drawable/textfield_default_filled" + android:tint="?android:attr/colorControlNormal" /> + </item> + <item android:state_pressed="false" android:state_focused="false"> + <nine-patch android:src="@drawable/textfield_default_filled" + android:tint="?android:attr/colorControlNormal" /> + </item> + <item> + <nine-patch android:src="@drawable/textfield_default_filled" + android:tint="?android:attr/colorControlActivated" /> + </item> + </selector> +</inset> diff --git a/packages/SystemUI/res/layout-land/auth_credential_password_view.xml b/packages/SystemUI/res/layout-land/auth_credential_password_view.xml index da76c8d0b11a..3bcc37a478c9 100644 --- a/packages/SystemUI/res/layout-land/auth_credential_password_view.xml +++ b/packages/SystemUI/res/layout-land/auth_credential_password_view.xml @@ -16,46 +16,74 @@ <com.android.systemui.biometrics.AuthCredentialPasswordView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:orientation="vertical" - android:gravity="center_horizontal" - android:elevation="@dimen/biometric_dialog_elevation"> + android:orientation="horizontal" + android:elevation="@dimen/biometric_dialog_elevation" + android:theme="?app:attr/lockPinPasswordStyle"> - <TextView - android:id="@+id/title" - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@style/TextAppearance.AuthCredential.Title"/> + <RelativeLayout + android:id="@+id/auth_credential_header" + style="?headerStyle" + android:layout_width="wrap_content" + android:layout_height="match_parent"> - <TextView - android:id="@+id/subtitle" - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@style/TextAppearance.AuthCredential.Subtitle"/> + <ImageView + android:id="@+id/icon" + style="?headerIconStyle" + android:layout_alignParentLeft="true" + android:layout_alignParentTop="true" + android:contentDescription="@null"/> - <TextView - android:id="@+id/description" - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@style/TextAppearance.AuthCredential.Description"/> + <TextView + android:id="@+id/title" + style="?titleTextAppearance" + android:layout_below="@id/icon" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> - <ImeAwareEditText - android:id="@+id/lockPassword" - android:layout_width="208dp" - android:layout_height="wrap_content" - android:layout_gravity="center_horizontal" - android:minHeight="48dp" - android:gravity="center" - android:inputType="textPassword" - android:maxLength="500" - android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii" - style="@style/TextAppearance.AuthCredential.PasswordEntry"/> - - <TextView - android:id="@+id/error" - android:layout_width="match_parent" + <TextView + android:id="@+id/subtitle" + style="?subTitleTextAppearance" + android:layout_below="@id/title" + android:layout_alignParentLeft="true" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + <TextView + android:id="@+id/description" + style="?descriptionTextAppearance" + android:layout_below="@id/subtitle" + android:layout_alignParentLeft="true" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + + </RelativeLayout> + + <LinearLayout + android:id="@+id/auth_credential_input" + android:layout_width="wrap_content" android:layout_height="wrap_content" - style="@style/TextAppearance.AuthCredential.Error"/> + android:orientation="vertical"> + + <ImeAwareEditText + android:id="@+id/lockPassword" + style="?passwordTextAppearance" + android:layout_width="208dp" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii" + android:inputType="textPassword" + android:minHeight="48dp" /> + + <TextView + android:id="@+id/error" + style="?errorTextAppearance" + android:layout_gravity="center" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> + + </LinearLayout> </com.android.systemui.biometrics.AuthCredentialPasswordView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml index 19a85fec1397..a3dd334bd667 100644 --- a/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml +++ b/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml @@ -16,91 +16,71 @@ <com.android.systemui.biometrics.AuthCredentialPatternView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" - android:elevation="@dimen/biometric_dialog_elevation"> + android:elevation="@dimen/biometric_dialog_elevation" + android:theme="?app:attr/lockPatternStyle"> - <LinearLayout + <RelativeLayout + android:id="@+id/auth_credential_header" + style="?headerStyle" android:layout_width="0dp" android:layout_height="match_parent" - android:layout_weight="1" - android:gravity="center" - android:orientation="vertical"> - - <Space - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_weight="1"/> + android:layout_weight="1"> <ImageView android:id="@+id/icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> + style="?headerIconStyle" + android:layout_alignParentLeft="true" + android:layout_alignParentTop="true" + android:contentDescription="@null"/> <TextView android:id="@+id/title" - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@style/TextAppearance.AuthCredential.Title"/> + style="?titleTextAppearance" + android:layout_below="@id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> <TextView android:id="@+id/subtitle" - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@style/TextAppearance.AuthCredential.Subtitle"/> + style="?subTitleTextAppearance" + android:layout_below="@id/title" + android:layout_alignParentLeft="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> <TextView android:id="@+id/description" - android:layout_width="match_parent" - android:layout_height="wrap_content" - style="@style/TextAppearance.AuthCredential.Description"/> + style="?descriptionTextAppearance" + android:layout_below="@id/subtitle" + android:layout_alignParentLeft="true" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> - <Space - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_weight="1"/> + </RelativeLayout> + + <FrameLayout + android:layout_weight="1" + style="?containerStyle" + android:layout_width="0dp" + android:layout_height="match_parent"> + + <com.android.internal.widget.LockPatternView + android:id="@+id/lockPattern" + android:layout_gravity="center" + android:layout_width="match_parent" + android:layout_height="match_parent"/> <TextView android:id="@+id/error" + style="?errorTextAppearance" android:layout_width="match_parent" android:layout_height="wrap_content" - style="@style/TextAppearance.AuthCredential.Error"/> - - <Space - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_weight="1"/> - - </LinearLayout> - - <LinearLayout - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:orientation="vertical" - android:gravity="center" - android:paddingLeft="0dp" - android:paddingRight="0dp" - android:paddingTop="0dp" - android:paddingBottom="16dp" - android:clipToPadding="false"> - - <FrameLayout - android:layout_width="wrap_content" - android:layout_height="0dp" - android:layout_weight="1" - style="@style/LockPatternContainerStyle"> - - <com.android.internal.widget.LockPatternView - android:id="@+id/lockPattern" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="center" - style="@style/LockPatternStyleBiometricPrompt"/> - - </FrameLayout> + android:layout_gravity="center_horizontal|bottom"/> - </LinearLayout> + </FrameLayout> </com.android.systemui.biometrics.AuthCredentialPatternView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/auth_credential_password_view.xml b/packages/SystemUI/res/layout/auth_credential_password_view.xml index 0ff1db2ef694..774b335f913e 100644 --- a/packages/SystemUI/res/layout/auth_credential_password_view.xml +++ b/packages/SystemUI/res/layout/auth_credential_password_view.xml @@ -16,74 +16,71 @@ <com.android.systemui.biometrics.AuthCredentialPasswordView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:elevation="@dimen/biometric_dialog_elevation" - android:orientation="vertical"> + android:orientation="vertical" + android:theme="?app:attr/lockPinPasswordStyle"> <RelativeLayout + android:id="@+id/auth_credential_header" + style="?headerStyle" android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> - - <LinearLayout - android:id="@+id/auth_credential_header" - style="@style/AuthCredentialHeaderStyle" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_alignParentTop="true"> + android:layout_height="match_parent"> - <ImageView - android:id="@+id/icon" - android:layout_width="48dp" - android:layout_height="48dp" - android:contentDescription="@null" /> + <ImageView + android:id="@+id/icon" + style="?headerIconStyle" + android:layout_alignParentLeft="true" + android:layout_alignParentTop="true" + android:contentDescription="@null"/> - <TextView - android:id="@+id/title" - style="@style/TextAppearance.AuthNonBioCredential.Title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - - <TextView - android:id="@+id/subtitle" - style="@style/TextAppearance.AuthNonBioCredential.Subtitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - - <TextView - android:id="@+id/description" - style="@style/TextAppearance.AuthNonBioCredential.Description" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> + <TextView + android:id="@+id/title" + style="?titleTextAppearance" + android:layout_below="@id/icon" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> - </LinearLayout> + <TextView + android:id="@+id/subtitle" + style="?subTitleTextAppearance" + android:layout_below="@id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content"/> - <LinearLayout + <TextView + android:id="@+id/description" + style="?descriptionTextAppearance" + android:layout_below="@id/subtitle" android:layout_width="match_parent" - android:layout_height="match_parent" - android:gravity="center" - android:orientation="vertical" - android:layout_alignParentBottom="true"> + android:layout_height="wrap_content"/> + </RelativeLayout> - <ImeAwareEditText - android:id="@+id/lockPassword" - style="@style/TextAppearance.AuthCredential.PasswordEntry" - android:layout_width="208dp" - android:layout_height="wrap_content" - android:layout_gravity="center" - android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii" - android:inputType="textPassword" - android:minHeight="48dp" /> + <LinearLayout + android:id="@+id/auth_credential_input" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> - <TextView - android:id="@+id/error" - style="@style/TextAppearance.AuthNonBioCredential.Error" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> + <ImeAwareEditText + android:id="@+id/lockPassword" + style="?passwordTextAppearance" + android:layout_width="208dp" + android:layout_height="wrap_content" + android:layout_gravity="center_horizontal" + android:imeOptions="actionNext|flagNoFullscreen|flagForceAscii" + android:inputType="textPassword" + android:minHeight="48dp" /> - </LinearLayout> + <TextView + android:id="@+id/error" + style="?errorTextAppearance" + android:layout_gravity="center_horizontal" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> - </RelativeLayout> + </LinearLayout> </com.android.systemui.biometrics.AuthCredentialPasswordView>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml index dada9813c320..4af997017bba 100644 --- a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml +++ b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml @@ -16,87 +16,66 @@ <com.android.systemui.biometrics.AuthCredentialPatternView xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" - android:gravity="center_horizontal" - android:elevation="@dimen/biometric_dialog_elevation"> + android:elevation="@dimen/biometric_dialog_elevation" + android:theme="?app:attr/lockPatternStyle"> <RelativeLayout + android:id="@+id/auth_credential_header" + style="?headerStyle" android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="vertical"> - - <LinearLayout - android:id="@+id/auth_credential_header" - style="@style/AuthCredentialHeaderStyle" - android:layout_width="match_parent" - android:layout_height="wrap_content"> - - <ImageView - android:id="@+id/icon" - android:layout_width="48dp" - android:layout_height="48dp" - android:contentDescription="@null" /> - - <TextView - android:id="@+id/title" - style="@style/TextAppearance.AuthNonBioCredential.Title" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - - <TextView - android:id="@+id/subtitle" - style="@style/TextAppearance.AuthNonBioCredential.Subtitle" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> + android:layout_height="wrap_content"> + + <ImageView + android:id="@+id/icon" + style="?headerIconStyle" + android:layout_alignParentLeft="true" + android:layout_alignParentTop="true" + android:contentDescription="@null"/> + + <TextView + android:id="@+id/title" + style="?titleTextAppearance" + android:layout_below="@id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <TextView + android:id="@+id/subtitle" + style="?subTitleTextAppearance" + android:layout_below="@id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + + <TextView + android:id="@+id/description" + style="?descriptionTextAppearance" + android:layout_below="@id/subtitle" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + </RelativeLayout> - <TextView - android:id="@+id/description" - style="@style/TextAppearance.AuthNonBioCredential.Description" - android:layout_width="wrap_content" - android:layout_height="wrap_content" /> - </LinearLayout> + <FrameLayout + android:id="@+id/auth_credential_container" + style="?containerStyle" + android:layout_width="match_parent" + android:layout_height="match_parent"> - <LinearLayout + <com.android.internal.widget.LockPatternView + android:id="@+id/lockPattern" + android:layout_gravity="center" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_below="@id/auth_credential_header" - android:gravity="center" - android:orientation="vertical" - android:paddingBottom="16dp" - android:paddingTop="60dp"> + android:layout_height="match_parent"/> - <FrameLayout - style="@style/LockPatternContainerStyle" - android:layout_width="wrap_content" - android:layout_height="0dp" - android:layout_weight="1"> - - <com.android.internal.widget.LockPatternView - android:id="@+id/lockPattern" - style="@style/LockPatternStyle" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="center" /> - - </FrameLayout> - - </LinearLayout> - - <LinearLayout + <TextView + android:id="@+id/error" + style="?errorTextAppearance" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_alignParentBottom="true"> - - <TextView - android:id="@+id/error" - style="@style/TextAppearance.AuthNonBioCredential.Error" - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - - </LinearLayout> - - </RelativeLayout> + android:layout_gravity="center_horizontal|bottom"/> + </FrameLayout> </com.android.systemui.biometrics.AuthCredentialPatternView>
\ No newline at end of file diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml index 89191984b9e8..aefd9981d02e 100644 --- a/packages/SystemUI/res/values-land/styles.xml +++ b/packages/SystemUI/res/values-land/styles.xml @@ -18,4 +18,42 @@ <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer"> <item name="android:layout_width">360dp</item> </style> + + <style name="AuthCredentialHeaderStyle"> + <item name="android:paddingStart">48dp</item> + <item name="android:paddingEnd">24dp</item> + <item name="android:paddingTop">48dp</item> + <item name="android:paddingBottom">10dp</item> + <item name="android:gravity">top|left</item> + </style> + + <style name="AuthCredentialPatternContainerStyle"> + <item name="android:gravity">center</item> + <item name="android:maxHeight">320dp</item> + <item name="android:maxWidth">320dp</item> + <item name="android:minHeight">200dp</item> + <item name="android:minWidth">200dp</item> + <item name="android:paddingHorizontal">60dp</item> + <item name="android:paddingVertical">20dp</item> + </style> + + <style name="TextAppearance.AuthNonBioCredential.Title"> + <item name="android:fontFamily">google-sans</item> + <item name="android:layout_marginTop">6dp</item> + <item name="android:textSize">36dp</item> + <item name="android:focusable">true</item> + </style> + + <style name="TextAppearance.AuthNonBioCredential.Subtitle"> + <item name="android:fontFamily">google-sans</item> + <item name="android:layout_marginTop">6dp</item> + <item name="android:textSize">18sp</item> + </style> + + <style name="TextAppearance.AuthNonBioCredential.Description"> + <item name="android:fontFamily">google-sans</item> + <item name="android:layout_marginTop">6dp</item> + <item name="android:textSize">18sp</item> + </style> + </resources> diff --git a/packages/SystemUI/res/values-sw600dp-land/styles.xml b/packages/SystemUI/res/values-sw600dp-land/styles.xml new file mode 100644 index 000000000000..8148d3dfaf7d --- /dev/null +++ b/packages/SystemUI/res/values-sw600dp-land/styles.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + + <style name="AuthCredentialPatternContainerStyle"> + <item name="android:gravity">center</item> + <item name="android:maxHeight">420dp</item> + <item name="android:maxWidth">420dp</item> + <item name="android:minHeight">200dp</item> + <item name="android:minWidth">200dp</item> + <item name="android:paddingHorizontal">120dp</item> + <item name="android:paddingVertical">40dp</item> + </style> + + <style name="TextAppearance.AuthNonBioCredential.Title"> + <item name="android:fontFamily">google-sans</item> + <item name="android:layout_marginTop">16dp</item> + <item name="android:textSize">36sp</item> + <item name="android:focusable">true</item> + </style> + + <style name="TextAppearance.AuthNonBioCredential.Subtitle"> + <item name="android:fontFamily">google-sans</item> + <item name="android:layout_marginTop">16dp</item> + <item name="android:textSize">18sp</item> + </style> + + <style name="TextAppearance.AuthNonBioCredential.Description"> + <item name="android:fontFamily">google-sans</item> + <item name="android:layout_marginTop">16dp</item> + <item name="android:textSize">18sp</item> + </style> +</resources> diff --git a/packages/SystemUI/res/values-sw600dp-port/styles.xml b/packages/SystemUI/res/values-sw600dp-port/styles.xml new file mode 100644 index 000000000000..771de08cb360 --- /dev/null +++ b/packages/SystemUI/res/values-sw600dp-port/styles.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + + <style name="AuthCredentialHeaderStyle"> + <item name="android:paddingStart">120dp</item> + <item name="android:paddingEnd">120dp</item> + <item name="android:paddingTop">80dp</item> + <item name="android:paddingBottom">10dp</item> + <item name="android:layout_gravity">top</item> + </style> + + <style name="AuthCredentialPatternContainerStyle"> + <item name="android:gravity">center</item> + <item name="android:maxHeight">420dp</item> + <item name="android:maxWidth">420dp</item> + <item name="android:minHeight">200dp</item> + <item name="android:minWidth">200dp</item> + <item name="android:paddingHorizontal">180dp</item> + <item name="android:paddingVertical">80dp</item> + </style> + + <style name="TextAppearance.AuthNonBioCredential.Title"> + <item name="android:fontFamily">google-sans</item> + <item name="android:layout_marginTop">24dp</item> + <item name="android:textSize">36sp</item> + <item name="android:focusable">true</item> + </style> + +</resources> diff --git a/packages/SystemUI/res/values-sw720dp-land/styles.xml b/packages/SystemUI/res/values-sw720dp-land/styles.xml new file mode 100644 index 000000000000..f9ed67d89de7 --- /dev/null +++ b/packages/SystemUI/res/values-sw720dp-land/styles.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + + <style name="AuthCredentialPatternContainerStyle"> + <item name="android:gravity">center</item> + <item name="android:maxHeight">420dp</item> + <item name="android:maxWidth">420dp</item> + <item name="android:minHeight">200dp</item> + <item name="android:minWidth">200dp</item> + <item name="android:paddingHorizontal">120dp</item> + <item name="android:paddingVertical">40dp</item> + </style> + + <style name="TextAppearance.AuthNonBioCredential.Title"> + <item name="android:fontFamily">google-sans</item> + <item name="android:layout_marginTop">16dp</item> + <item name="android:textSize">36sp</item> + <item name="android:focusable">true</item> + </style> + + <style name="TextAppearance.AuthNonBioCredential.Subtitle"> + <item name="android:fontFamily">google-sans</item> + <item name="android:layout_marginTop">16dp</item> + <item name="android:textSize">18sp</item> + </style> + + <style name="TextAppearance.AuthNonBioCredential.Description"> + <item name="android:fontFamily">google-sans</item> + <item name="android:layout_marginTop">16dp</item> + <item name="android:textSize">18sp</item> + </style> + +</resources> diff --git a/packages/SystemUI/res/values-sw720dp-port/styles.xml b/packages/SystemUI/res/values-sw720dp-port/styles.xml new file mode 100644 index 000000000000..78d299c483e6 --- /dev/null +++ b/packages/SystemUI/res/values-sw720dp-port/styles.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2022 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources xmlns:android="http://schemas.android.com/apk/res/android"> + + <style name="AuthCredentialHeaderStyle"> + <item name="android:paddingStart">120dp</item> + <item name="android:paddingEnd">120dp</item> + <item name="android:paddingTop">80dp</item> + <item name="android:paddingBottom">10dp</item> + <item name="android:layout_gravity">top</item> + </style> + + <style name="AuthCredentialPatternContainerStyle"> + <item name="android:gravity">center</item> + <item name="android:maxHeight">420dp</item> + <item name="android:maxWidth">420dp</item> + <item name="android:minHeight">200dp</item> + <item name="android:minWidth">200dp</item> + <item name="android:paddingHorizontal">240dp</item> + <item name="android:paddingVertical">120dp</item> + </style> + + <style name="TextAppearance.AuthNonBioCredential.Title"> + <item name="android:fontFamily">google-sans</item> + <item name="android:layout_marginTop">24dp</item> + <item name="android:textSize">36sp</item> + <item name="android:focusable">true</item> + </style> + +</resources> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index 9a71995383ac..df0659d67afe 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -191,5 +191,18 @@ <declare-styleable name="DelayableMarqueeTextView"> <attr name="marqueeDelay" format="integer" /> </declare-styleable> + + <declare-styleable name="AuthCredentialView"> + <attr name="lockPatternStyle" format="reference" /> + <attr name="lockPinPasswordStyle" format="reference" /> + <attr name="containerStyle" format="reference" /> + <attr name="headerStyle" format="reference" /> + <attr name="headerIconStyle" format="reference" /> + <attr name="titleTextAppearance" format="reference" /> + <attr name="subTitleTextAppearance" format="reference" /> + <attr name="descriptionTextAppearance" format="reference" /> + <attr name="passwordTextAppearance" format="reference" /> + <attr name="errorTextAppearance" format="reference"/> + </declare-styleable> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index cf100cb04a7b..93926ef9e780 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -950,6 +950,9 @@ <dimen name="biometric_dialog_width">240dp</dimen> <dimen name="biometric_dialog_height">240dp</dimen> + <!-- Biometric Auth Credential values --> + <dimen name="biometric_auth_icon_size">48dp</dimen> + <!-- Starting text size in sp of batteryLevel for wireless charging animation --> <item name="wireless_charging_anim_battery_level_text_size_start" format="float" type="dimen"> 0 diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index b5011dfaf6eb..e76887babc50 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -197,8 +197,9 @@ <style name="TextAppearance.AuthNonBioCredential.Title"> <item name="android:fontFamily">google-sans</item> - <item name="android:layout_marginTop">20dp</item> - <item name="android:textSize">36sp</item> + <item name="android:layout_marginTop">24dp</item> + <item name="android:textSize">36dp</item> + <item name="android:focusable">true</item> </style> <style name="TextAppearance.AuthNonBioCredential.Subtitle"> @@ -210,12 +211,10 @@ <style name="TextAppearance.AuthNonBioCredential.Description"> <item name="android:fontFamily">google-sans</item> <item name="android:layout_marginTop">20dp</item> - <item name="android:textSize">16sp</item> + <item name="android:textSize">18sp</item> </style> <style name="TextAppearance.AuthNonBioCredential.Error"> - <item name="android:paddingTop">6dp</item> - <item name="android:paddingBottom">18dp</item> <item name="android:paddingHorizontal">24dp</item> <item name="android:textSize">14sp</item> <item name="android:textColor">?android:attr/colorError</item> @@ -224,20 +223,43 @@ <style name="TextAppearance.AuthCredential.PasswordEntry" parent="@android:style/TextAppearance.DeviceDefault"> <item name="android:gravity">center</item> + <item name="android:paddingTop">28dp</item> <item name="android:singleLine">true</item> <item name="android:textColor">?android:attr/colorForeground</item> <item name="android:textSize">24sp</item> + <item name="android:background">@drawable/edit_text_filled</item> </style> <style name="AuthCredentialHeaderStyle"> <item name="android:paddingStart">48dp</item> - <item name="android:paddingEnd">24dp</item> - <item name="android:paddingTop">28dp</item> - <item name="android:paddingBottom">20dp</item> - <item name="android:orientation">vertical</item> + <item name="android:paddingEnd">48dp</item> + <item name="android:paddingTop">48dp</item> + <item name="android:paddingBottom">10dp</item> <item name="android:layout_gravity">top</item> </style> + <style name="AuthCredentialIconStyle"> + <item name="android:layout_width">@dimen/biometric_auth_icon_size</item> + <item name="android:layout_height">@dimen/biometric_auth_icon_size</item> + </style> + + <style name="AuthCredentialPatternContainerStyle"> + <item name="android:gravity">center</item> + <item name="android:maxHeight">420dp</item> + <item name="android:maxWidth">420dp</item> + <item name="android:minHeight">200dp</item> + <item name="android:minWidth">200dp</item> + <item name="android:padding">20dp</item> + </style> + + <style name="AuthCredentialPinPasswordContainerStyle"> + <item name="android:gravity">center</item> + <item name="android:maxHeight">48dp</item> + <item name="android:maxWidth">600dp</item> + <item name="android:minHeight">48dp</item> + <item name="android:minWidth">200dp</item> + </style> + <style name="DeviceManagementDialogTitle"> <item name="android:gravity">center</item> <item name="android:textAppearance">@style/TextAppearance.DeviceManagementDialog.Title</item> @@ -275,7 +297,9 @@ <item name="wallpaperTextColorSecondary">@*android:color/secondary_text_material_dark</item> <item name="wallpaperTextColorAccent">@color/material_dynamic_primary90</item> <item name="android:colorError">@*android:color/error_color_material_dark</item> - <item name="*android:lockPatternStyle">@style/LockPatternStyle</item> + <item name="*android:lockPatternStyle">@style/LockPatternViewStyle</item> + <item name="lockPatternStyle">@style/LockPatternContainerStyle</item> + <item name="lockPinPasswordStyle">@style/LockPinPasswordContainerStyle</item> <item name="passwordStyle">@style/PasswordTheme</item> <item name="numPadKeyStyle">@style/NumPadKey</item> <item name="backgroundProtectedStyle">@style/BackgroundProtectedStyle</item> @@ -301,27 +325,33 @@ <item name="android:textColor">?attr/wallpaperTextColor</item> </style> - <style name="LockPatternContainerStyle"> - <item name="android:maxHeight">400dp</item> - <item name="android:maxWidth">420dp</item> - <item name="android:minHeight">0dp</item> - <item name="android:minWidth">0dp</item> - <item name="android:paddingHorizontal">60dp</item> - <item name="android:paddingBottom">40dp</item> + <style name="AuthCredentialStyle"> + <item name="*android:regularColor">?android:attr/colorForeground</item> + <item name="*android:successColor">?android:attr/colorForeground</item> + <item name="*android:errorColor">?android:attr/colorError</item> + <item name="*android:dotColor">?android:attr/textColorSecondary</item> + <item name="headerStyle">@style/AuthCredentialHeaderStyle</item> + <item name="headerIconStyle">@style/AuthCredentialIconStyle</item> + <item name="titleTextAppearance">@style/TextAppearance.AuthNonBioCredential.Title</item> + <item name="subTitleTextAppearance">@style/TextAppearance.AuthNonBioCredential.Subtitle</item> + <item name="descriptionTextAppearance">@style/TextAppearance.AuthNonBioCredential.Description</item> + <item name="passwordTextAppearance">@style/TextAppearance.AuthCredential.PasswordEntry</item> + <item name="errorTextAppearance">@style/TextAppearance.AuthNonBioCredential.Error</item> </style> - <style name="LockPatternStyle"> + <style name="LockPatternViewStyle" > <item name="*android:regularColor">?android:attr/colorAccent</item> <item name="*android:successColor">?android:attr/textColorPrimary</item> <item name="*android:errorColor">?android:attr/colorError</item> <item name="*android:dotColor">?android:attr/textColorSecondary</item> </style> - <style name="LockPatternStyleBiometricPrompt"> - <item name="*android:regularColor">?android:attr/colorForeground</item> - <item name="*android:successColor">?android:attr/colorForeground</item> - <item name="*android:errorColor">?android:attr/colorError</item> - <item name="*android:dotColor">?android:attr/textColorSecondary</item> + <style name="LockPatternContainerStyle" parent="@style/AuthCredentialStyle"> + <item name="containerStyle">@style/AuthCredentialPatternContainerStyle</item> + </style> + + <style name="LockPinPasswordContainerStyle" parent="@style/AuthCredentialStyle"> + <item name="containerStyle">@style/AuthCredentialPinPasswordContainerStyle</item> </style> <style name="Theme.SystemUI.QuickSettings" parent="@*android:style/Theme.DeviceDefault"> diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt index 2e391c7aacbe..49cc48321d77 100644 --- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt +++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt @@ -19,6 +19,7 @@ package com.android.systemui.testing.screenshot import android.app.Activity import android.graphics.Color import android.view.View +import android.view.Window import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat @@ -51,13 +52,14 @@ class ExternalViewScreenshotTestRule(emulationSpec: DeviceEmulationSpec) : TestR /** * Compare the content of the [view] with the golden image identified by [goldenIdentifier] in - * the context of [emulationSpec]. + * the context of [emulationSpec]. Window must be specified to capture views that render + * hardware buffers. */ - fun screenshotTest(goldenIdentifier: String, view: View) { + fun screenshotTest(goldenIdentifier: String, view: View, window: Window? = null) { view.removeElevationRecursively() ScreenshotRuleAsserter.Builder(screenshotRule) - .setScreenshotProvider { view.toBitmap() } + .setScreenshotProvider { view.toBitmap(window) } .withMatcher(matcher) .build() .assertGoldenImage(goldenIdentifier) @@ -94,6 +96,6 @@ class ExternalViewScreenshotTestRule(emulationSpec: DeviceEmulationSpec) : TestR activity.currentFocus?.clearFocus() } - screenshotTest(goldenIdentifier, rootView) + screenshotTest(goldenIdentifier, rootView, activity.window) } } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java index 72f8b7b09dca..40c8774d4f34 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java @@ -1,13 +1,16 @@ package com.android.systemui.shared.recents.utilities; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; +import static android.view.Surface.ROTATION_180; +import static android.view.Surface.ROTATION_270; +import static android.view.Surface.ROTATION_90; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.RectF; -import android.view.Surface; import com.android.systemui.shared.recents.model.ThumbnailData; +import com.android.wm.shell.util.SplitBounds; /** * Utility class to position the thumbnail in the TaskView @@ -16,10 +19,26 @@ public class PreviewPositionHelper { public static final float MAX_PCT_BEFORE_ASPECT_RATIOS_CONSIDERED_DIFFERENT = 0.1f; + /** + * Specifies that a stage is positioned at the top half of the screen if + * in portrait mode or at the left half of the screen if in landscape mode. + * TODO(b/254378592): Remove after consolidation + */ + public static final int STAGE_POSITION_TOP_OR_LEFT = 0; + + /** + * Specifies that a stage is positioned at the bottom half of the screen if + * in portrait mode or at the right half of the screen if in landscape mode. + * TODO(b/254378592): Remove after consolidation + */ + public static final int STAGE_POSITION_BOTTOM_OR_RIGHT = 1; + // Contains the portion of the thumbnail that is unclipped when fullscreen progress = 1. private final RectF mClippedInsets = new RectF(); private final Matrix mMatrix = new Matrix(); private boolean mIsOrientationChanged; + private SplitBounds mSplitBounds; + private int mDesiredStagePosition; public Matrix getMatrix() { return mMatrix; @@ -33,6 +52,11 @@ public class PreviewPositionHelper { return mIsOrientationChanged; } + public void setSplitBounds(SplitBounds splitBounds, int desiredStagePosition) { + mSplitBounds = splitBounds; + mDesiredStagePosition = desiredStagePosition; + } + /** * Updates the matrix based on the provided parameters */ @@ -42,10 +66,19 @@ public class PreviewPositionHelper { boolean isRotated = false; boolean isOrientationDifferent; + float fullscreenTaskWidth = screenWidthPx; + if (mSplitBounds != null && !mSplitBounds.appsStackedVertically) { + // For landscape, scale the width + float taskPercent = mDesiredStagePosition == STAGE_POSITION_TOP_OR_LEFT + ? mSplitBounds.leftTaskPercent + : (1 - (mSplitBounds.leftTaskPercent + mSplitBounds.dividerWidthPercent)); + // Scale landscape width to that of actual screen + fullscreenTaskWidth = screenWidthPx * taskPercent; + } int thumbnailRotation = thumbnailData.rotation; int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation); RectF thumbnailClipHint = new RectF(); - float canvasScreenRatio = canvasWidth / (float) screenWidthPx; + float canvasScreenRatio = canvasWidth / fullscreenTaskWidth; float scaledTaskbarSize = taskbarSize * canvasScreenRatio; thumbnailClipHint.bottom = isTablet ? scaledTaskbarSize : 0; @@ -180,7 +213,7 @@ public class PreviewPositionHelper { * portrait or vice versa, {@code false} otherwise */ private boolean isOrientationChange(int deltaRotation) { - return deltaRotation == Surface.ROTATION_90 || deltaRotation == Surface.ROTATION_270; + return deltaRotation == ROTATION_90 || deltaRotation == ROTATION_270; } private void setThumbnailRotation(int deltaRotate, Rect thumbnailPosition) { @@ -189,13 +222,13 @@ public class PreviewPositionHelper { mMatrix.setRotate(90 * deltaRotate); switch (deltaRotate) { /* Counter-clockwise */ - case Surface.ROTATION_90: + case ROTATION_90: translateX = thumbnailPosition.height(); break; - case Surface.ROTATION_270: + case ROTATION_270: translateY = thumbnailPosition.width(); break; - case Surface.ROTATION_180: + case ROTATION_180: translateX = thumbnailPosition.width(); translateY = thumbnailPosition.height(); break; diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java index 0892612d1825..76cd3f4c4f1d 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPasswordView.java @@ -16,12 +16,21 @@ package com.android.systemui.biometrics; +import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; +import static android.view.WindowInsets.Type.ime; + import android.annotation.NonNull; import android.content.Context; +import android.graphics.Insets; import android.os.UserHandle; import android.text.InputType; +import android.text.TextUtils; import android.util.AttributeSet; import android.view.KeyEvent; +import android.view.View; +import android.view.View.OnApplyWindowInsetsListener; +import android.view.ViewGroup; +import android.view.WindowInsets; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.ImeAwareEditText; @@ -31,18 +40,24 @@ import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockscreenCredential; import com.android.internal.widget.VerifyCredentialResponse; +import com.android.systemui.Dumpable; import com.android.systemui.R; +import java.io.PrintWriter; + /** * Pin and Password UI */ public class AuthCredentialPasswordView extends AuthCredentialView - implements TextView.OnEditorActionListener { + implements TextView.OnEditorActionListener, OnApplyWindowInsetsListener, Dumpable { private static final String TAG = "BiometricPrompt/AuthCredentialPasswordView"; private final InputMethodManager mImm; private ImeAwareEditText mPasswordField; + private ViewGroup mAuthCredentialHeader; + private ViewGroup mAuthCredentialInput; + private int mBottomInset = 0; public AuthCredentialPasswordView(Context context, AttributeSet attrs) { @@ -53,6 +68,9 @@ public class AuthCredentialPasswordView extends AuthCredentialView @Override protected void onFinishInflate() { super.onFinishInflate(); + + mAuthCredentialHeader = findViewById(R.id.auth_credential_header); + mAuthCredentialInput = findViewById(R.id.auth_credential_input); mPasswordField = findViewById(R.id.lockPassword); mPasswordField.setOnEditorActionListener(this); // TODO: De-dupe the logic with AuthContainerView @@ -66,6 +84,8 @@ public class AuthCredentialPasswordView extends AuthCredentialView } return true; }); + + setOnApplyWindowInsetsListener(this); } @Override @@ -127,4 +147,92 @@ public class AuthCredentialPasswordView extends AuthCredentialView mPasswordField.setText(""); } } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + + if (mAuthCredentialInput == null || mAuthCredentialHeader == null || mSubtitleView == null + || mDescriptionView == null || mPasswordField == null || mErrorView == null) { + return; + } + + int inputLeftBound; + int inputTopBound; + int headerRightBound = right; + int headerTopBounds = top; + final int subTitleBottom = (mSubtitleView.getVisibility() == GONE) ? mTitleView.getBottom() + : mSubtitleView.getBottom(); + final int descBottom = (mDescriptionView.getVisibility() == GONE) ? subTitleBottom + : mDescriptionView.getBottom(); + if (getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE) { + inputTopBound = (bottom - mAuthCredentialInput.getHeight()) / 2; + inputLeftBound = (right - left) / 2; + headerRightBound = inputLeftBound; + headerTopBounds -= Math.min(mIconView.getBottom(), mBottomInset); + } else { + inputTopBound = + descBottom + (bottom - descBottom - mAuthCredentialInput.getHeight()) / 2; + inputLeftBound = (right - left - mAuthCredentialInput.getWidth()) / 2; + } + + if (mDescriptionView.getBottom() > mBottomInset) { + mAuthCredentialHeader.layout(left, headerTopBounds, headerRightBound, bottom); + } + mAuthCredentialInput.layout(inputLeftBound, inputTopBound, right, bottom); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + final int newWidth = MeasureSpec.getSize(widthMeasureSpec); + final int newHeight = MeasureSpec.getSize(heightMeasureSpec) - mBottomInset; + + setMeasuredDimension(newWidth, newHeight); + + final int halfWidthSpec = MeasureSpec.makeMeasureSpec(getWidth() / 2, + MeasureSpec.AT_MOST); + final int fullHeightSpec = MeasureSpec.makeMeasureSpec(newHeight, MeasureSpec.UNSPECIFIED); + if (getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE) { + measureChildren(halfWidthSpec, fullHeightSpec); + } else { + measureChildren(widthMeasureSpec, fullHeightSpec); + } + } + + @NonNull + @Override + public WindowInsets onApplyWindowInsets(@NonNull View v, WindowInsets insets) { + + final Insets bottomInset = insets.getInsets(ime()); + if (v instanceof AuthCredentialPasswordView && mBottomInset != bottomInset.bottom) { + mBottomInset = bottomInset.bottom; + if (mBottomInset > 0 + && getResources().getConfiguration().orientation == ORIENTATION_LANDSCAPE) { + mTitleView.setSingleLine(true); + mTitleView.setEllipsize(TextUtils.TruncateAt.MARQUEE); + mTitleView.setMarqueeRepeatLimit(-1); + // select to enable marquee unless a screen reader is enabled + mTitleView.setSelected(!mAccessibilityManager.isEnabled() + || !mAccessibilityManager.isTouchExplorationEnabled()); + } else { + mTitleView.setSingleLine(false); + mTitleView.setEllipsize(null); + // select to enable marquee unless a screen reader is enabled + mTitleView.setSelected(false); + } + requestLayout(); + } + return insets; + } + + @Override + public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { + pw.println(TAG + "State:"); + pw.println(" mBottomInset=" + mBottomInset); + pw.println(" mAuthCredentialHeader size=(" + mAuthCredentialHeader.getWidth() + "," + + mAuthCredentialHeader.getHeight()); + pw.println(" mAuthCredentialInput size=(" + mAuthCredentialInput.getWidth() + "," + + mAuthCredentialInput.getHeight()); + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java index 11498dbc0b83..f9e44a0c1724 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialPatternView.java @@ -93,7 +93,9 @@ public class AuthCredentialPatternView extends AuthCredentialView { @Override protected void onErrorTimeoutFinish() { super.onErrorTimeoutFinish(); - mLockPatternView.setEnabled(true); + // select to enable marquee unless a screen reader is enabled + mLockPatternView.setEnabled(!mAccessibilityManager.isEnabled() + || !mAccessibilityManager.isTouchExplorationEnabled()); } public AuthCredentialPatternView(Context context, AttributeSet attrs) { diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java index 4fa835e038ec..5958e6a436f1 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthCredentialView.java @@ -30,7 +30,6 @@ import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.pm.UserInfo; import android.graphics.drawable.Drawable; -import android.hardware.biometrics.BiometricPrompt; import android.hardware.biometrics.PromptInfo; import android.os.AsyncTask; import android.os.CountDownTimer; @@ -77,7 +76,7 @@ public abstract class AuthCredentialView extends LinearLayout { protected final Handler mHandler; protected final LockPatternUtils mLockPatternUtils; - private final AccessibilityManager mAccessibilityManager; + protected final AccessibilityManager mAccessibilityManager; private final UserManager mUserManager; private final DevicePolicyManager mDevicePolicyManager; @@ -86,10 +85,10 @@ public abstract class AuthCredentialView extends LinearLayout { private boolean mShouldAnimatePanel; private boolean mShouldAnimateContents; - private TextView mTitleView; - private TextView mSubtitleView; - private TextView mDescriptionView; - private ImageView mIconView; + protected TextView mTitleView; + protected TextView mSubtitleView; + protected TextView mDescriptionView; + protected ImageView mIconView; protected TextView mErrorView; protected @Utils.CredentialType int mCredentialType; diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index 027187c889b4..00a9ddff1368 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -363,6 +363,10 @@ public class Flags { // 1700 - clipboard public static final UnreleasedFlag CLIPBOARD_OVERLAY_REFACTOR = new UnreleasedFlag(1700); + // 1800 - shade container + public static final UnreleasedFlag LEAVE_SHADE_OPEN_FOR_BUGREPORT = + new UnreleasedFlag(1800, true); + // Pay no attention to the reflection behind the curtain. // ========================== Curtain ========================== // | | diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java index da5819a7f3bc..3ef5499237f1 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java @@ -116,6 +116,7 @@ import com.android.systemui.MultiListLayout; import com.android.systemui.MultiListLayout.MultiListAdapter; import com.android.systemui.animation.DialogCuj; import com.android.systemui.animation.DialogLaunchAnimator; +import com.android.systemui.animation.Expandable; import com.android.systemui.animation.Interpolators; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.colorextraction.SysuiColorExtractor; @@ -448,10 +449,11 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene * * @param keyguardShowing True if keyguard is showing * @param isDeviceProvisioned True if device is provisioned - * @param view The view from which we should animate the dialog when showing it + * @param expandable The expandable from which we should animate the dialog when + * showing it */ public void showOrHideDialog(boolean keyguardShowing, boolean isDeviceProvisioned, - @Nullable View view) { + @Nullable Expandable expandable) { mKeyguardShowing = keyguardShowing; mDeviceProvisioned = isDeviceProvisioned; if (mDialog != null && mDialog.isShowing()) { @@ -463,7 +465,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene mDialog.dismiss(); mDialog = null; } else { - handleShow(view); + handleShow(expandable); } } @@ -495,7 +497,7 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene } } - protected void handleShow(@Nullable View view) { + protected void handleShow(@Nullable Expandable expandable) { awakenIfNecessary(); mDialog = createDialog(); prepareDialog(); @@ -507,10 +509,12 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene // Don't acquire soft keyboard focus, to avoid destroying state when capturing bugreports mDialog.getWindow().addFlags(FLAG_ALT_FOCUSABLE_IM); - if (view != null) { - mDialogLaunchAnimator.showFromView(mDialog, view, - new DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, - INTERACTION_JANK_TAG)); + DialogLaunchAnimator.Controller controller = + expandable != null ? expandable.dialogLaunchController( + new DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, + INTERACTION_JANK_TAG)) : null; + if (controller != null) { + mDialogLaunchAnimator.show(mDialog, controller); } else { mDialog.show(); } @@ -1016,8 +1020,9 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene Log.w(TAG, "Bugreport handler could not be launched"); mIActivityManager.requestInteractiveBugReport(); } - // Close shade so user sees the activity - mCentralSurfacesOptional.ifPresent(CentralSurfaces::collapseShade); + // Maybe close shade (depends on a flag) so user sees the activity + mCentralSurfacesOptional.ifPresent( + CentralSurfaces::collapseShadeForBugreport); } catch (RemoteException e) { } } @@ -1036,8 +1041,8 @@ public class GlobalActionsDialogLite implements DialogInterface.OnDismissListene mMetricsLogger.action(MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL); mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS); mIActivityManager.requestFullBugReport(); - // Close shade so user sees the activity - mCentralSurfacesOptional.ifPresent(CentralSurfaces::collapseShade); + // Maybe close shade (depends on a flag) so user sees the activity + mCentralSurfacesOptional.ifPresent(CentralSurfaces::collapseShadeForBugreport); } catch (RemoteException e) { } return false; diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt index 1ac2a078c8a0..be357ee0ff73 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt @@ -182,8 +182,7 @@ class MediaProjectionAppSelectorActivity( override fun shouldGetOnlyDefaultActivities() = false - // TODO(b/240924732) flip the flag when the recents selector is ready - override fun shouldShowContentPreview() = false + override fun shouldShowContentPreview() = true override fun createContentPreviewView(parent: ViewGroup): ViewGroup = recentsViewController.createView(parent) diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt index 482a1397642b..bb2b4419a80a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt @@ -52,6 +52,7 @@ import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogLaunchAnimator +import com.android.systemui.animation.Expandable import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Background @@ -98,10 +99,10 @@ interface FgsManagerController { fun init() /** - * Show the foreground services dialog. The dialog will be expanded from [viewLaunchedFrom] if + * Show the foreground services dialog. The dialog will be expanded from [expandable] if * it's not `null`. */ - fun showDialog(viewLaunchedFrom: View?) + fun showDialog(expandable: Expandable?) /** Add a [OnNumberOfPackagesChangedListener]. */ fun addOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener) @@ -367,7 +368,7 @@ class FgsManagerControllerImpl @Inject constructor( override fun shouldUpdateFooterVisibility() = dialog == null - override fun showDialog(viewLaunchedFrom: View?) { + override fun showDialog(expandable: Expandable?) { synchronized(lock) { if (dialog == null) { @@ -403,16 +404,18 @@ class FgsManagerControllerImpl @Inject constructor( } mainExecutor.execute { - viewLaunchedFrom - ?.let { - dialogLaunchAnimator.showFromView( - dialog, it, - cuj = DialogCuj( - InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, - INTERACTION_JANK_TAG - ) + val controller = + expandable?.dialogLaunchController( + DialogCuj( + InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, + INTERACTION_JANK_TAG, ) - } ?: dialog.show() + ) + if (controller != null) { + dialogLaunchAnimator.show(dialog, controller) + } else { + dialog.show() + } } backgroundExecutor.execute { diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt index 9d64781ef2e9..a9943e886339 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt @@ -32,6 +32,7 @@ import com.android.internal.logging.nano.MetricsProto import com.android.keyguard.KeyguardUpdateMonitor import com.android.systemui.R import com.android.systemui.animation.ActivityLaunchAnimator +import com.android.systemui.animation.Expandable import com.android.systemui.globalactions.GlobalActionsDialogLite import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager @@ -156,7 +157,7 @@ internal class FooterActionsController @Inject constructor( startSettingsActivity() } else if (v === powerMenuLite) { uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS) - globalActionsDialog?.showOrHideDialog(false, true, v) + globalActionsDialog?.showOrHideDialog(false, true, Expandable.fromView(powerMenuLite)) } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java index 7511278e0919..b1b9dd721eaf 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFgsManagerFooter.java @@ -29,6 +29,7 @@ import android.widget.TextView; import androidx.annotation.Nullable; import com.android.systemui.R; +import com.android.systemui.animation.Expandable; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.qs.dagger.QSScope; @@ -130,7 +131,7 @@ public class QSFgsManagerFooter implements View.OnClickListener, @Override public void onClick(View view) { - mFgsManagerController.showDialog(mRootView); + mFgsManagerController.showDialog(Expandable.fromView(view)); } public void refreshState() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java index 67bf3003deff..6c1e95645550 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java @@ -39,6 +39,7 @@ import androidx.annotation.Nullable; import com.android.internal.util.FrameworkStatsLog; import com.android.systemui.FontSizeUtils; import com.android.systemui.R; +import com.android.systemui.animation.Expandable; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.common.shared.model.Icon; import com.android.systemui.dagger.qualifiers.Background; @@ -169,7 +170,7 @@ public class QSSecurityFooter extends ViewController<View> // TODO(b/242040009): Remove this. public void showDeviceMonitoringDialog() { - mQSSecurityFooterUtils.showDeviceMonitoringDialog(mContext, mView); + mQSSecurityFooterUtils.showDeviceMonitoringDialog(mContext, Expandable.fromView(mView)); } public void refreshState() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java index ae6ed2008a77..67bc76998597 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java @@ -75,6 +75,7 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.systemui.R; import com.android.systemui.animation.DialogCuj; import com.android.systemui.animation.DialogLaunchAnimator; +import com.android.systemui.animation.Expandable; import com.android.systemui.common.shared.model.ContentDescription; import com.android.systemui.common.shared.model.Icon; import com.android.systemui.dagger.SysUISingleton; @@ -190,8 +191,9 @@ public class QSSecurityFooterUtils implements DialogInterface.OnClickListener { } /** Show the device monitoring dialog. */ - public void showDeviceMonitoringDialog(Context quickSettingsContext, @Nullable View view) { - createDialog(quickSettingsContext, view); + public void showDeviceMonitoringDialog(Context quickSettingsContext, + @Nullable Expandable expandable) { + createDialog(quickSettingsContext, expandable); } /** @@ -440,7 +442,7 @@ public class QSSecurityFooterUtils implements DialogInterface.OnClickListener { } } - private void createDialog(Context quickSettingsContext, @Nullable View view) { + private void createDialog(Context quickSettingsContext, @Nullable Expandable expandable) { mShouldUseSettingsButton.set(false); mBgHandler.post(() -> { String settingsButtonText = getSettingsButton(); @@ -453,9 +455,12 @@ public class QSSecurityFooterUtils implements DialogInterface.OnClickListener { ? settingsButtonText : getNegativeButton(), this); mDialog.setView(dialogView); - if (view != null && view.isAggregatedVisible()) { - mDialogLaunchAnimator.showFromView(mDialog, view, new DialogCuj( - InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG)); + DialogLaunchAnimator.Controller controller = + expandable != null ? expandable.dialogLaunchController(new DialogCuj( + InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG)) + : null; + if (controller != null) { + mDialogLaunchAnimator.show(mDialog, controller); } else { mDialog.show(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt index cf9b41c25388..9ba3501c3434 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractor.kt @@ -23,13 +23,11 @@ import android.content.Intent import android.content.IntentFilter import android.os.UserHandle import android.provider.Settings -import android.view.View import com.android.internal.jank.InteractionJankMonitor import com.android.internal.logging.MetricsLogger import com.android.internal.logging.UiEventLogger import com.android.internal.logging.nano.MetricsProto import com.android.internal.util.FrameworkStatsLog -import com.android.systemui.animation.ActivityLaunchAnimator import com.android.systemui.animation.Expandable import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.SysUISingleton @@ -74,37 +72,27 @@ interface FooterActionsInteractor { val deviceMonitoringDialogRequests: Flow<Unit> /** - * Show the device monitoring dialog, expanded from [view]. - * - * Important: [view] must be associated to the same [Context] as the [Quick Settings fragment] - * [com.android.systemui.qs.QSFragment]. - */ - // TODO(b/230830644): Replace view by Expandable interface. - fun showDeviceMonitoringDialog(view: View) - - /** - * Show the device monitoring dialog. + * Show the device monitoring dialog, expanded from [expandable] if it's not null. * * Important: [quickSettingsContext] *must* be the [Context] associated to the [Quick Settings * fragment][com.android.systemui.qs.QSFragment]. */ - // TODO(b/230830644): Replace view by Expandable interface. - fun showDeviceMonitoringDialog(quickSettingsContext: Context) + fun showDeviceMonitoringDialog(quickSettingsContext: Context, expandable: Expandable?) /** Show the foreground services dialog. */ - // TODO(b/230830644): Replace view by Expandable interface. - fun showForegroundServicesDialog(view: View) + fun showForegroundServicesDialog(expandable: Expandable) /** Show the power menu dialog. */ - // TODO(b/230830644): Replace view by Expandable interface. - fun showPowerMenuDialog(globalActionsDialogLite: GlobalActionsDialogLite, view: View) + fun showPowerMenuDialog( + globalActionsDialogLite: GlobalActionsDialogLite, + expandable: Expandable, + ) /** Show the settings. */ fun showSettings(expandable: Expandable) /** Show the user switcher. */ - // TODO(b/230830644): Replace view by Expandable interface. - fun showUserSwitcher(view: View) + fun showUserSwitcher(context: Context, expandable: Expandable) } @SysUISingleton @@ -147,28 +135,32 @@ constructor( null, ) - override fun showDeviceMonitoringDialog(view: View) { - qsSecurityFooterUtils.showDeviceMonitoringDialog(view.context, view) - DevicePolicyEventLogger.createEvent( - FrameworkStatsLog.DEVICE_POLICY_EVENT__EVENT_ID__DO_USER_INFO_CLICKED - ) - .write() - } - - override fun showDeviceMonitoringDialog(quickSettingsContext: Context) { - qsSecurityFooterUtils.showDeviceMonitoringDialog(quickSettingsContext, /* view= */ null) + override fun showDeviceMonitoringDialog( + quickSettingsContext: Context, + expandable: Expandable?, + ) { + qsSecurityFooterUtils.showDeviceMonitoringDialog(quickSettingsContext, expandable) + if (expandable != null) { + DevicePolicyEventLogger.createEvent( + FrameworkStatsLog.DEVICE_POLICY_EVENT__EVENT_ID__DO_USER_INFO_CLICKED + ) + .write() + } } - override fun showForegroundServicesDialog(view: View) { - fgsManagerController.showDialog(view) + override fun showForegroundServicesDialog(expandable: Expandable) { + fgsManagerController.showDialog(expandable) } - override fun showPowerMenuDialog(globalActionsDialogLite: GlobalActionsDialogLite, view: View) { + override fun showPowerMenuDialog( + globalActionsDialogLite: GlobalActionsDialogLite, + expandable: Expandable, + ) { uiEventLogger.log(GlobalActionsDialogLite.GlobalActionsEvent.GA_OPEN_QS) globalActionsDialogLite.showOrHideDialog( /* keyguardShowing= */ false, /* isDeviceProvisioned= */ true, - view, + expandable, ) } @@ -189,21 +181,21 @@ constructor( ) } - override fun showUserSwitcher(view: View) { + override fun showUserSwitcher(context: Context, expandable: Expandable) { if (!featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) { - userSwitchDialogController.showDialog(view) + userSwitchDialogController.showDialog(context, expandable) return } val intent = - Intent(view.context, UserSwitcherActivity::class.java).apply { + Intent(context, UserSwitcherActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) } activityStarter.startActivity( intent, true /* dismissShade */, - ActivityLaunchAnimator.Controller.fromView(view, null), + expandable.activityLaunchController(), true /* showOverlockscreenwhenlocked */, UserHandle.SYSTEM, ) diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt index dd1ffcc9fa12..3e39c8ee62f1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt @@ -31,6 +31,7 @@ import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.R +import com.android.systemui.animation.Expandable import com.android.systemui.common.ui.binder.IconViewBinder import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.people.ui.view.PeopleViewBinder.bind @@ -125,7 +126,7 @@ object FooterActionsViewBinder { launch { viewModel.security.collect { security -> if (previousSecurity != security) { - bindSecurity(securityHolder, security) + bindSecurity(view.context, securityHolder, security) previousSecurity = security } } @@ -159,6 +160,7 @@ object FooterActionsViewBinder { } private fun bindSecurity( + quickSettingsContext: Context, securityHolder: TextButtonViewHolder, security: FooterActionsSecurityButtonViewModel?, ) { @@ -171,9 +173,12 @@ object FooterActionsViewBinder { // Make sure that the chevron is visible and that the button is clickable if there is a // listener. val chevron = securityHolder.chevron - if (security.onClick != null) { + val onClick = security.onClick + if (onClick != null) { securityView.isClickable = true - securityView.setOnClickListener(security.onClick) + securityView.setOnClickListener { + onClick(quickSettingsContext, Expandable.fromView(securityView)) + } chevron.isVisible = true } else { securityView.isClickable = false @@ -205,7 +210,9 @@ object FooterActionsViewBinder { foregroundServicesWithNumberView.isVisible = false foregroundServicesWithTextView.isVisible = true - foregroundServicesWithTextView.setOnClickListener(foregroundServices.onClick) + foregroundServicesWithTextView.setOnClickListener { + foregroundServices.onClick(Expandable.fromView(foregroundServicesWithTextView)) + } foregroundServicesWithTextHolder.text.text = foregroundServices.text foregroundServicesWithTextHolder.newDot.isVisible = foregroundServices.hasNewChanges } else { @@ -213,7 +220,9 @@ object FooterActionsViewBinder { foregroundServicesWithTextView.isVisible = false foregroundServicesWithNumberView.visibility = View.VISIBLE - foregroundServicesWithNumberView.setOnClickListener(foregroundServices.onClick) + foregroundServicesWithNumberView.setOnClickListener { + foregroundServices.onClick(Expandable.fromView(foregroundServicesWithTextView)) + } foregroundServicesWithNumberHolder.number.text = foregroundServicesCount.toString() foregroundServicesWithNumberHolder.number.contentDescription = foregroundServices.text foregroundServicesWithNumberHolder.newDot.isVisible = foregroundServices.hasNewChanges @@ -229,7 +238,7 @@ object FooterActionsViewBinder { } buttonView.setBackgroundResource(model.background) - buttonView.setOnClickListener(model.onClick) + buttonView.setOnClickListener { model.onClick(Expandable.fromView(buttonView)) } val icon = model.icon val iconView = button.icon diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt index 9b5f683d8dab..8d819dacba67 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt @@ -17,7 +17,7 @@ package com.android.systemui.qs.footer.ui.viewmodel import android.annotation.DrawableRes -import android.view.View +import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon /** @@ -29,7 +29,5 @@ data class FooterActionsButtonViewModel( val icon: Icon, val iconTint: Int?, @DrawableRes val background: Int, - // TODO(b/230830644): Replace View by an Expandable interface that can expand in either dialog - // or activity. - val onClick: (View) -> Unit, + val onClick: (Expandable) -> Unit, ) diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsForegroundServicesButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsForegroundServicesButtonViewModel.kt index 98b53cb0ed5a..ff8130d3e6ec 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsForegroundServicesButtonViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsForegroundServicesButtonViewModel.kt @@ -16,7 +16,7 @@ package com.android.systemui.qs.footer.ui.viewmodel -import android.view.View +import com.android.systemui.animation.Expandable /** A ViewModel for the foreground services button. */ data class FooterActionsForegroundServicesButtonViewModel( @@ -24,5 +24,5 @@ data class FooterActionsForegroundServicesButtonViewModel( val text: String, val displayText: Boolean, val hasNewChanges: Boolean, - val onClick: (View) -> Unit, + val onClick: (Expandable) -> Unit, ) diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsSecurityButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsSecurityButtonViewModel.kt index 98ab129fc9de..3450505f9f86 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsSecurityButtonViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsSecurityButtonViewModel.kt @@ -16,12 +16,13 @@ package com.android.systemui.qs.footer.ui.viewmodel -import android.view.View +import android.content.Context +import com.android.systemui.animation.Expandable import com.android.systemui.common.shared.model.Icon /** A ViewModel for the security button. */ data class FooterActionsSecurityButtonViewModel( val icon: Icon, val text: String, - val onClick: ((View) -> Unit)?, + val onClick: ((quickSettingsContext: Context, Expandable) -> Unit)?, ) diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt index d3c06f60bc90..dee6fadbc9cb 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt @@ -18,7 +18,6 @@ package com.android.systemui.qs.footer.ui.viewmodel import android.content.Context import android.util.Log -import android.view.View import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner @@ -199,50 +198,51 @@ class FooterActionsViewModel( */ suspend fun observeDeviceMonitoringDialogRequests(quickSettingsContext: Context) { footerActionsInteractor.deviceMonitoringDialogRequests.collect { - footerActionsInteractor.showDeviceMonitoringDialog(quickSettingsContext) + footerActionsInteractor.showDeviceMonitoringDialog( + quickSettingsContext, + expandable = null, + ) } } - private fun onSecurityButtonClicked(view: View) { + private fun onSecurityButtonClicked(quickSettingsContext: Context, expandable: Expandable) { if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return } - footerActionsInteractor.showDeviceMonitoringDialog(view) + footerActionsInteractor.showDeviceMonitoringDialog(quickSettingsContext, expandable) } - private fun onForegroundServiceButtonClicked(view: View) { + private fun onForegroundServiceButtonClicked(expandable: Expandable) { if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return } - footerActionsInteractor.showForegroundServicesDialog(view) + footerActionsInteractor.showForegroundServicesDialog(expandable) } - private fun onUserSwitcherClicked(view: View) { + private fun onUserSwitcherClicked(expandable: Expandable) { if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return } - footerActionsInteractor.showUserSwitcher(view) + footerActionsInteractor.showUserSwitcher(context, expandable) } - // TODO(b/230830644): Replace View by an Expandable interface that can expand in either dialog - // or activity. - private fun onSettingsButtonClicked(view: View) { + private fun onSettingsButtonClicked(expandable: Expandable) { if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return } - footerActionsInteractor.showSettings(Expandable.fromView(view)) + footerActionsInteractor.showSettings(expandable) } - private fun onPowerButtonClicked(view: View) { + private fun onPowerButtonClicked(expandable: Expandable) { if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) { return } - footerActionsInteractor.showPowerMenuDialog(globalActionsDialogLite, view) + footerActionsInteractor.showPowerMenuDialog(globalActionsDialogLite, expandable) } private fun userSwitcherButton( diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt index bdcc6b0b2a57..314252bf310b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt @@ -23,13 +23,13 @@ import android.content.DialogInterface.BUTTON_NEUTRAL import android.content.Intent import android.provider.Settings import android.view.LayoutInflater -import android.view.View import androidx.annotation.VisibleForTesting import com.android.internal.jank.InteractionJankMonitor import com.android.internal.logging.UiEventLogger import com.android.systemui.R import com.android.systemui.animation.DialogCuj import com.android.systemui.animation.DialogLaunchAnimator +import com.android.systemui.animation.Expandable import com.android.systemui.dagger.SysUISingleton import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager @@ -77,10 +77,10 @@ class UserSwitchDialogController @VisibleForTesting constructor( * Show a [UserDialog]. * * Populate the dialog with information from and adapter obtained from - * [userDetailViewAdapterProvider] and show it as launched from [view]. + * [userDetailViewAdapterProvider] and show it as launched from [expandable]. */ - fun showDialog(view: View) { - with(dialogFactory(view.context)) { + fun showDialog(context: Context, expandable: Expandable) { + with(dialogFactory(context)) { setShowForAllUsers(true) setCanceledOnTouchOutside(true) @@ -112,13 +112,19 @@ class UserSwitchDialogController @VisibleForTesting constructor( adapter.linkToViewGroup(gridFrame.findViewById(R.id.grid)) - dialogLaunchAnimator.showFromView( - this, view, - cuj = DialogCuj( - InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, - INTERACTION_JANK_TAG + val controller = + expandable.dialogLaunchController( + DialogCuj(InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG) ) - ) + if (controller != null) { + dialogLaunchAnimator.show( + this, + controller, + ) + } else { + show() + } + uiEventLogger.log(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN) adapter.injectDialogShower(DialogShowerImpl(this, dialogLaunchAnimator)) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt index 8f3eb4f7e223..8a31ed9271ad 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt @@ -18,6 +18,8 @@ package com.android.systemui.statusbar.notification.collection.coordinator import android.app.Notification import android.app.Notification.GROUP_ALERT_SUMMARY import android.util.ArrayMap +import android.util.ArraySet +import com.android.internal.annotations.VisibleForTesting import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.NotificationRemoteInputManager import com.android.systemui.statusbar.notification.collection.GroupEntry @@ -70,6 +72,7 @@ class HeadsUpCoordinator @Inject constructor( @Main private val mExecutor: DelayableExecutor, ) : Coordinator { private val mEntriesBindingUntil = ArrayMap<String, Long>() + private val mEntriesUpdateTimes = ArrayMap<String, Long>() private var mEndLifetimeExtension: OnEndLifetimeExtensionCallback? = null private lateinit var mNotifPipeline: NotifPipeline private var mNow: Long = -1 @@ -264,6 +267,9 @@ class HeadsUpCoordinator @Inject constructor( } // After this method runs, all posted entries should have been handled (or skipped). mPostedEntries.clear() + + // Also take this opportunity to clean up any stale entry update times + cleanUpEntryUpdateTimes() } /** @@ -378,6 +384,9 @@ class HeadsUpCoordinator @Inject constructor( isAlerting = false, isBinding = false, ) + + // Record the last updated time for this key + setUpdateTime(entry, mSystemClock.currentTimeMillis()) } /** @@ -419,6 +428,9 @@ class HeadsUpCoordinator @Inject constructor( cancelHeadsUpBind(posted.entry) } } + + // Update last updated time for this entry + setUpdateTime(entry, mSystemClock.currentTimeMillis()) } /** @@ -426,6 +438,7 @@ class HeadsUpCoordinator @Inject constructor( */ override fun onEntryRemoved(entry: NotificationEntry, reason: Int) { mPostedEntries.remove(entry.key) + mEntriesUpdateTimes.remove(entry.key) cancelHeadsUpBind(entry) val entryKey = entry.key if (mHeadsUpManager.isAlerting(entryKey)) { @@ -454,7 +467,12 @@ class HeadsUpCoordinator @Inject constructor( // never) in mPostedEntries to need to alert, we need to check every notification // known to the pipeline. for (entry in mNotifPipeline.allNotifs) { - // The only entries we can consider alerting for here are entries that have never + // Only consider entries that are recent enough, since we want to apply a fairly + // strict threshold for when an entry should be updated via only ranking and not an + // app-provided notification update. + if (!isNewEnoughForRankingUpdate(entry)) continue + + // The only entries we consider alerting for here are entries that have never // interrupted and that now say they should heads up; if they've alerted in the // past, we don't want to incorrectly alert a second time if there wasn't an // explicit notification update. @@ -486,6 +504,41 @@ class HeadsUpCoordinator @Inject constructor( (entry.sbn.notification.flags and Notification.FLAG_ONLY_ALERT_ONCE) == 0) } + /** + * Sets the updated time for the given entry to the specified time. + */ + @VisibleForTesting + fun setUpdateTime(entry: NotificationEntry, time: Long) { + mEntriesUpdateTimes[entry.key] = time + } + + /** + * Checks whether the entry is new enough to be updated via ranking update. + * We want to avoid updating an entry too long after it was originally posted/updated when we're + * only reacting to a ranking change, as relevant ranking updates are expected to come in + * fairly soon after the posting of a notification. + */ + private fun isNewEnoughForRankingUpdate(entry: NotificationEntry): Boolean { + // If we don't have an update time for this key, default to "too old" + if (!mEntriesUpdateTimes.containsKey(entry.key)) return false + + val updateTime = mEntriesUpdateTimes[entry.key] ?: return false + return (mSystemClock.currentTimeMillis() - updateTime) <= MAX_RANKING_UPDATE_DELAY_MS + } + + private fun cleanUpEntryUpdateTimes() { + // Because we won't update entries that are older than this amount of time anyway, clean + // up any entries that are too old to notify. + val toRemove = ArraySet<String>() + for ((key, updateTime) in mEntriesUpdateTimes) { + if (updateTime == null || + (mSystemClock.currentTimeMillis() - updateTime) > MAX_RANKING_UPDATE_DELAY_MS) { + toRemove.add(key) + } + } + mEntriesUpdateTimes.removeAll(toRemove) + } + /** When an action is pressed on a notification, end HeadsUp lifetime extension. */ private val mActionPressListener = Consumer<NotificationEntry> { entry -> if (mNotifsExtendingLifetime.contains(entry)) { @@ -597,6 +650,9 @@ class HeadsUpCoordinator @Inject constructor( companion object { private const val TAG = "HeadsUpCoordinator" private const val BIND_TIMEOUT = 1000L + + // This value is set to match MAX_SOUND_DELAY_MS in NotificationRecord. + private const val MAX_RANKING_UPDATE_DELAY_MS: Long = 2000 } data class PostedEntry( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java index fa7bfaeb6c4d..2180d89bb18e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java @@ -455,6 +455,9 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn void collapseShade(); + /** Collapse the shade, but conditional on a flag specific to the trigger of a bugreport. */ + void collapseShadeForBugreport(); + int getWakefulnessState(); boolean isScreenFullyOff(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java index 604e1467f950..489a1993af3a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java @@ -885,6 +885,11 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { mBubblesOptional.get().setExpandListener(mBubbleExpandListener); } + // Do not restart System UI when the bugreport flag changes. + mFeatureFlags.addListener(Flags.LEAVE_SHADE_OPEN_FOR_BUGREPORT, event -> { + event.requestNoRestart(); + }); + mStatusBarSignalPolicy.init(); mKeyguardIndicationController.init(); @@ -3580,6 +3585,13 @@ public class CentralSurfacesImpl implements CoreStartable, CentralSurfaces { } } + @Override + public void collapseShadeForBugreport() { + if (!mFeatureFlags.isEnabled(Flags.LEAVE_SHADE_OPEN_FOR_BUGREPORT)) { + collapseShade(); + } + } + @VisibleForTesting final WakefulnessLifecycle.Observer mWakefulnessObserver = new WakefulnessLifecycle.Observer() { @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java index 00c3e8fac0b4..5e2a7c8ca540 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitchController.java @@ -26,6 +26,7 @@ import android.view.ViewGroup; import com.android.systemui.R; import com.android.systemui.animation.ActivityLaunchAnimator; +import com.android.systemui.animation.Expandable; import com.android.systemui.flags.FeatureFlags; import com.android.systemui.flags.Flags; import com.android.systemui.plugins.ActivityStarter; @@ -67,7 +68,7 @@ public class MultiUserSwitchController extends ViewController<MultiUserSwitch> { ActivityLaunchAnimator.Controller.fromView(v, null), true /* showOverlockscreenwhenlocked */, UserHandle.SYSTEM); } else { - mUserSwitchDialogController.showDialog(v); + mUserSwitchDialogController.showDialog(v.getContext(), Expandable.fromView(v)); } } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt index 0d52f46e571f..e498ae451400 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherController.kt @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone.userswitcher import android.content.Intent import android.os.UserHandle import android.view.View +import com.android.systemui.animation.Expandable import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.plugins.ActivityStarter @@ -75,7 +76,7 @@ class StatusBarUserSwitcherControllerImpl @Inject constructor( null /* ActivityLaunchAnimator.Controller */, true /* showOverlockscreenwhenlocked */, UserHandle.SYSTEM) } else { - userSwitcherDialogController.showDialog(view) + userSwitcherDialogController.showDialog(view.context, Expandable.fromView(view)) } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java index dc73d1f007c6..f63d65246d9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java @@ -36,6 +36,7 @@ import com.android.keyguard.KeyguardVisibilityHelper; import com.android.keyguard.dagger.KeyguardUserSwitcherScope; import com.android.settingslib.drawable.CircleFramedDrawable; import com.android.systemui.R; +import com.android.systemui.animation.Expandable; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -190,7 +191,8 @@ public class KeyguardQsUserSwitchController extends ViewController<FrameLayout> mUiEventLogger.log( LockscreenGestureLogger.LockscreenUiEvent.LOCKSCREEN_SWITCH_USER_TAP); - mUserSwitchDialogController.showDialog(mUserAvatarViewWithBackground); + mUserSwitchDialogController.showDialog(mUserAvatarViewWithBackground.getContext(), + Expandable.fromView(mUserAvatarViewWithBackground)); }); mUserAvatarView.setAccessibilityDelegate(new View.AccessibilityDelegate() { diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/Condition.java b/packages/SystemUI/src/com/android/systemui/util/condition/Condition.java index ecb365f43e3f..2c317dd391c0 100644 --- a/packages/SystemUI/src/com/android/systemui/util/condition/Condition.java +++ b/packages/SystemUI/src/com/android/systemui/util/condition/Condition.java @@ -172,10 +172,14 @@ public abstract class Condition implements CallbackController<Condition.Callback return Boolean.TRUE.equals(mIsConditionMet); } - private boolean shouldLog() { + protected final boolean shouldLog() { return Log.isLoggable(mTag, Log.DEBUG); } + protected final String getTag() { + return mTag; + } + /** * Callback that receives updates about whether the condition has been fulfilled. */ diff --git a/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java b/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java index 4824f6744c6e..cb430ba454f0 100644 --- a/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java +++ b/packages/SystemUI/src/com/android/systemui/util/condition/Monitor.java @@ -117,6 +117,7 @@ public class Monitor { final SubscriptionState state = new SubscriptionState(subscription); mExecutor.execute(() -> { + if (shouldLog()) Log.d(mTag, "adding subscription"); mSubscriptions.put(token, state); // Add and associate conditions. @@ -143,7 +144,7 @@ public class Monitor { */ public void removeSubscription(@NotNull Subscription.Token token) { mExecutor.execute(() -> { - if (shouldLog()) Log.d(mTag, "removing callback"); + if (shouldLog()) Log.d(mTag, "removing subscription"); if (!mSubscriptions.containsKey(token)) { Log.e(mTag, "subscription not present:" + token); return; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java index 1c686c66e31e..5e9c1aaad309 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java @@ -22,7 +22,6 @@ import static junit.framework.Assert.assertNotNull; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -52,6 +51,7 @@ import android.text.SpannableStringBuilder; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.FrameLayout; import android.widget.TextView; import com.android.systemui.R; @@ -97,6 +97,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { private static final int DEFAULT_ICON_ID = R.drawable.ic_info_outline; private ViewGroup mRootView; + private ViewGroup mSecurityFooterView; private TextView mFooterText; private TestableImageView mPrimaryFooterIcon; private QSSecurityFooter mFooter; @@ -121,21 +122,26 @@ public class QSSecurityFooterTest extends SysuiTestCase { Looper looper = mTestableLooper.getLooper(); Handler mainHandler = new Handler(looper); when(mUserTracker.getUserInfo()).thenReturn(mock(UserInfo.class)); - mRootView = (ViewGroup) new LayoutInflaterBuilder(mContext) + mSecurityFooterView = (ViewGroup) new LayoutInflaterBuilder(mContext) .replace("ImageView", TestableImageView.class) .build().inflate(R.layout.quick_settings_security_footer, null, false); mFooterUtils = new QSSecurityFooterUtils(getContext(), getContext().getSystemService(DevicePolicyManager.class), mUserTracker, mainHandler, mActivityStarter, mSecurityController, looper, mDialogLaunchAnimator); - mFooter = new QSSecurityFooter(mRootView, mainHandler, mSecurityController, looper, - mBroadcastDispatcher, mFooterUtils); - mFooterText = mRootView.findViewById(R.id.footer_text); - mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon); + mFooter = new QSSecurityFooter(mSecurityFooterView, mainHandler, mSecurityController, + looper, mBroadcastDispatcher, mFooterUtils); + mFooterText = mSecurityFooterView.findViewById(R.id.footer_text); + mPrimaryFooterIcon = mSecurityFooterView.findViewById(R.id.primary_footer_icon); when(mSecurityController.getDeviceOwnerComponentOnAnyUser()) .thenReturn(DEVICE_OWNER_COMPONENT); when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT)) .thenReturn(DEVICE_OWNER_TYPE_DEFAULT); + + // mSecurityFooterView must have a ViewGroup parent so that + // DialogLaunchAnimator.Controller.fromView() does not return null. + mRootView = new FrameLayout(mContext); + mRootView.addView(mSecurityFooterView); ViewUtils.attachView(mRootView); mFooter.init(); @@ -153,7 +159,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { mFooter.refreshState(); TestableLooper.get(this).processAllMessages(); - assertEquals(View.GONE, mRootView.getVisibility()); + assertEquals(View.GONE, mSecurityFooterView.getVisibility()); } @Test @@ -165,7 +171,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { TestableLooper.get(this).processAllMessages(); assertEquals(mContext.getString(R.string.quick_settings_disclosure_management), mFooterText.getText()); - assertEquals(View.VISIBLE, mRootView.getVisibility()); + assertEquals(View.VISIBLE, mSecurityFooterView.getVisibility()); assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); } @@ -181,7 +187,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { assertEquals(mContext.getString(R.string.quick_settings_disclosure_named_management, MANAGING_ORGANIZATION), mFooterText.getText()); - assertEquals(View.VISIBLE, mRootView.getVisibility()); + assertEquals(View.VISIBLE, mSecurityFooterView.getVisibility()); assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); } @@ -200,7 +206,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { assertEquals(mContext.getString( R.string.quick_settings_financed_disclosure_named_management, MANAGING_ORGANIZATION), mFooterText.getText()); - assertEquals(View.VISIBLE, mRootView.getVisibility()); + assertEquals(View.VISIBLE, mSecurityFooterView.getVisibility()); assertEquals(View.VISIBLE, mPrimaryFooterIcon.getVisibility()); assertEquals(DEFAULT_ICON_ID, mPrimaryFooterIcon.getLastImageResource()); } @@ -217,7 +223,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { mFooter.refreshState(); TestableLooper.get(this).processAllMessages(); - assertEquals(View.GONE, mRootView.getVisibility()); + assertEquals(View.GONE, mSecurityFooterView.getVisibility()); } @Test @@ -227,8 +233,8 @@ public class QSSecurityFooterTest extends SysuiTestCase { mFooter.refreshState(); TestableLooper.get(this).processAllMessages(); - assertFalse(mRootView.isClickable()); - assertEquals(View.GONE, mRootView.findViewById(R.id.footer_icon).getVisibility()); + assertFalse(mSecurityFooterView.isClickable()); + assertEquals(View.GONE, mSecurityFooterView.findViewById(R.id.footer_icon).getVisibility()); } @Test @@ -241,8 +247,9 @@ public class QSSecurityFooterTest extends SysuiTestCase { mFooter.refreshState(); TestableLooper.get(this).processAllMessages(); - assertTrue(mRootView.isClickable()); - assertEquals(View.VISIBLE, mRootView.findViewById(R.id.footer_icon).getVisibility()); + assertTrue(mSecurityFooterView.isClickable()); + assertEquals(View.VISIBLE, + mSecurityFooterView.findViewById(R.id.footer_icon).getVisibility()); } @Test @@ -254,8 +261,8 @@ public class QSSecurityFooterTest extends SysuiTestCase { mFooter.refreshState(); TestableLooper.get(this).processAllMessages(); - assertFalse(mRootView.isClickable()); - assertEquals(View.GONE, mRootView.findViewById(R.id.footer_icon).getVisibility()); + assertFalse(mSecurityFooterView.isClickable()); + assertEquals(View.GONE, mSecurityFooterView.findViewById(R.id.footer_icon).getVisibility()); } @Test @@ -734,11 +741,11 @@ public class QSSecurityFooterTest extends SysuiTestCase { @Test public void testDialogUsesDialogLauncher() { when(mSecurityController.isDeviceManaged()).thenReturn(true); - mFooter.onClick(mRootView); + mFooter.onClick(mSecurityFooterView); mTestableLooper.processAllMessages(); - verify(mDialogLaunchAnimator).showFromView(any(), eq(mRootView), any()); + verify(mDialogLaunchAnimator).show(any(), any()); } @Test @@ -775,7 +782,7 @@ public class QSSecurityFooterTest extends SysuiTestCase { ArgumentCaptor<AlertDialog> dialogCaptor = ArgumentCaptor.forClass(AlertDialog.class); mTestableLooper.processAllMessages(); - verify(mDialogLaunchAnimator).showFromView(dialogCaptor.capture(), any(), any()); + verify(mDialogLaunchAnimator).show(dialogCaptor.capture(), any()); AlertDialog dialog = dialogCaptor.getValue(); dialog.create(); @@ -817,8 +824,8 @@ public class QSSecurityFooterTest extends SysuiTestCase { verify(mBroadcastDispatcher).registerReceiverWithHandler(captor.capture(), any(), any(), any()); - // Pretend view is not visible temporarily - mRootView.onVisibilityAggregated(false); + // Pretend view is not attached anymore. + mRootView.removeView(mSecurityFooterView); captor.getValue().onReceive(mContext, new Intent(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG)); mTestableLooper.processAllMessages(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt index 3c258077c29d..2c2ddbb9b8c5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt @@ -23,13 +23,13 @@ import android.os.UserHandle import android.provider.Settings import android.testing.AndroidTestingRunner import android.testing.TestableLooper -import android.view.View import androidx.test.filters.SmallTest import com.android.internal.logging.nano.MetricsProto import com.android.internal.logging.testing.FakeMetricsLogger import com.android.internal.logging.testing.UiEventLoggerFake import com.android.systemui.SysuiTestCase import com.android.systemui.animation.ActivityLaunchAnimator +import com.android.systemui.animation.Expandable import com.android.systemui.flags.FakeFeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.globalactions.GlobalActionsDialogLite @@ -70,13 +70,13 @@ class FooterActionsInteractorTest : SysuiTestCase() { val underTest = utils.footerActionsInteractor(qsSecurityFooterUtils = qsSecurityFooterUtils) val quickSettingsContext = mock<Context>() - underTest.showDeviceMonitoringDialog(quickSettingsContext) - verify(qsSecurityFooterUtils).showDeviceMonitoringDialog(quickSettingsContext, null) - val view = mock<View>() - whenever(view.context).thenReturn(quickSettingsContext) - underTest.showDeviceMonitoringDialog(view) + underTest.showDeviceMonitoringDialog(quickSettingsContext, null) verify(qsSecurityFooterUtils).showDeviceMonitoringDialog(quickSettingsContext, null) + + val expandable = mock<Expandable>() + underTest.showDeviceMonitoringDialog(quickSettingsContext, expandable) + verify(qsSecurityFooterUtils).showDeviceMonitoringDialog(quickSettingsContext, expandable) } @Test @@ -85,8 +85,8 @@ class FooterActionsInteractorTest : SysuiTestCase() { val underTest = utils.footerActionsInteractor(uiEventLogger = uiEventLogger) val globalActionsDialogLite = mock<GlobalActionsDialogLite>() - val view = mock<View>() - underTest.showPowerMenuDialog(globalActionsDialogLite, view) + val expandable = mock<Expandable>() + underTest.showPowerMenuDialog(globalActionsDialogLite, expandable) // Event is logged. val logs = uiEventLogger.logs @@ -99,7 +99,7 @@ class FooterActionsInteractorTest : SysuiTestCase() { .showOrHideDialog( /* keyguardShowing= */ false, /* isDeviceProvisioned= */ true, - view, + expandable, ) } @@ -167,11 +167,11 @@ class FooterActionsInteractorTest : SysuiTestCase() { userSwitchDialogController = userSwitchDialogController, ) - val view = mock<View>() - underTest.showUserSwitcher(view) + val expandable = mock<Expandable>() + underTest.showUserSwitcher(context, expandable) // Dialog is shown. - verify(userSwitchDialogController).showDialog(view) + verify(userSwitchDialogController).showDialog(context, expandable) } @Test @@ -184,12 +184,9 @@ class FooterActionsInteractorTest : SysuiTestCase() { activityStarter = activityStarter, ) - // The clicked view. The context is necessary because it's used to build the intent, that - // we check below. - val view = mock<View>() - whenever(view.context).thenReturn(context) - - underTest.showUserSwitcher(view) + // The clicked expandable. + val expandable = mock<Expandable>() + underTest.showUserSwitcher(context, expandable) // Dialog is shown. val intentCaptor = argumentCaptor<Intent>() diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt index 9d908fdfb976..0a34810f4d3f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/user/UserSwitchDialogControllerTest.kt @@ -20,12 +20,12 @@ import android.content.DialogInterface import android.content.Intent import android.provider.Settings import android.testing.AndroidTestingRunner -import android.view.View import android.widget.Button import androidx.test.filters.SmallTest import com.android.internal.logging.UiEventLogger import com.android.systemui.SysuiTestCase import com.android.systemui.animation.DialogLaunchAnimator +import com.android.systemui.animation.Expandable import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager import com.android.systemui.qs.PseudoGridView @@ -35,6 +35,7 @@ import com.android.systemui.statusbar.phone.SystemUIDialog import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.mock import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -63,7 +64,7 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { @Mock private lateinit var userDetailViewAdapter: UserDetailView.Adapter @Mock - private lateinit var launchView: View + private lateinit var launchExpandable: Expandable @Mock private lateinit var neutralButton: Button @Mock @@ -79,7 +80,6 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { fun setUp() { MockitoAnnotations.initMocks(this) - `when`(launchView.context).thenReturn(mContext) `when`(dialog.context).thenReturn(mContext) controller = UserSwitchDialogController( @@ -94,32 +94,34 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { @Test fun showDialog_callsDialogShow() { - controller.showDialog(launchView) - verify(dialogLaunchAnimator).showFromView(eq(dialog), eq(launchView), any(), anyBoolean()) + val launchController = mock<DialogLaunchAnimator.Controller>() + `when`(launchExpandable.dialogLaunchController(any())).thenReturn(launchController) + controller.showDialog(context, launchExpandable) + verify(dialogLaunchAnimator).show(eq(dialog), eq(launchController), anyBoolean()) verify(uiEventLogger).log(QSUserSwitcherEvent.QS_USER_DETAIL_OPEN) } @Test fun dialog_showForAllUsers() { - controller.showDialog(launchView) + controller.showDialog(context, launchExpandable) verify(dialog).setShowForAllUsers(true) } @Test fun dialog_cancelOnTouchOutside() { - controller.showDialog(launchView) + controller.showDialog(context, launchExpandable) verify(dialog).setCanceledOnTouchOutside(true) } @Test fun adapterAndGridLinked() { - controller.showDialog(launchView) + controller.showDialog(context, launchExpandable) verify(userDetailViewAdapter).linkToViewGroup(any<PseudoGridView>()) } @Test fun doneButtonLogsCorrectly() { - controller.showDialog(launchView) + controller.showDialog(context, launchExpandable) verify(dialog).setPositiveButton(anyInt(), capture(clickCaptor)) @@ -132,7 +134,7 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { fun clickSettingsButton_noFalsing_opensSettings() { `when`(falsingManager.isFalseTap(anyInt())).thenReturn(false) - controller.showDialog(launchView) + controller.showDialog(context, launchExpandable) verify(dialog) .setNeutralButton(anyInt(), capture(clickCaptor), eq(false) /* dismissOnClick */) @@ -153,7 +155,7 @@ class UserSwitchDialogControllerTest : SysuiTestCase() { fun clickSettingsButton_Falsing_notOpensSettings() { `when`(falsingManager.isFalseTap(anyInt())).thenReturn(true) - controller.showDialog(launchView) + controller.showDialog(context, launchExpandable) verify(dialog) .setNeutralButton(anyInt(), capture(clickCaptor), eq(false) /* dismissOnClick */) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt index 340bc96f80c2..3ff7639e9262 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt @@ -674,7 +674,9 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { @Test fun testOnRankingApplied_newEntryShouldAlert() { // GIVEN that mEntry has never interrupted in the past, and now should + // and is new enough to do so assertFalse(mEntry.hasInterrupted()) + mCoordinator.setUpdateTime(mEntry, mSystemClock.currentTimeMillis()) setShouldHeadsUp(mEntry) whenever(mNotifPipeline.allNotifs).thenReturn(listOf(mEntry)) @@ -690,8 +692,9 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { @Test fun testOnRankingApplied_alreadyAlertedEntryShouldNotAlertAgain() { - // GIVEN that mEntry has alerted in the past + // GIVEN that mEntry has alerted in the past, even if it's new mEntry.setInterruption() + mCoordinator.setUpdateTime(mEntry, mSystemClock.currentTimeMillis()) setShouldHeadsUp(mEntry) whenever(mNotifPipeline.allNotifs).thenReturn(listOf(mEntry)) @@ -725,6 +728,27 @@ class HeadsUpCoordinatorTest : SysuiTestCase() { verify(mHeadsUpManager).showNotification(mEntry) } + @Test + fun testOnRankingApplied_entryUpdatedButTooOld() { + // GIVEN that mEntry is added in a state where it should not HUN + setShouldHeadsUp(mEntry, false) + mCollectionListener.onEntryAdded(mEntry) + + // and it was actually added 10s ago + mCoordinator.setUpdateTime(mEntry, mSystemClock.currentTimeMillis() - 10000) + + // WHEN it is updated to HUN and then a ranking update occurs + setShouldHeadsUp(mEntry) + whenever(mNotifPipeline.allNotifs).thenReturn(listOf(mEntry)) + mCollectionListener.onRankingApplied() + mBeforeTransformGroupsListener.onBeforeTransformGroups(listOf(mEntry)) + mBeforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(mEntry)) + + // THEN the notification is never bound or shown + verify(mHeadsUpViewBinder, never()).bindHeadsUpView(any(), any()) + verify(mHeadsUpManager, never()).showNotification(any()) + } + private fun setShouldHeadsUp(entry: NotificationEntry, should: Boolean = true) { whenever(mNotificationInterruptStateProvider.shouldHeadsUp(entry)).thenReturn(should) whenever(mNotificationInterruptStateProvider.checkHeadsUp(eq(entry), any())) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java index ad497a2ec1e1..d4cd4a608340 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java @@ -98,7 +98,8 @@ import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.demomode.DemoModeController; import com.android.systemui.dump.DumpManager; -import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.FakeFeatureFlags; +import com.android.systemui.flags.Flags; import com.android.systemui.fragments.FragmentService; import com.android.systemui.keyguard.KeyguardUnlockAnimationController; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -271,7 +272,6 @@ public class CentralSurfacesImplTest extends SysuiTestCase { @Mock private OngoingCallController mOngoingCallController; @Mock private StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; @Mock private LockscreenShadeTransitionController mLockscreenTransitionController; - @Mock private FeatureFlags mFeatureFlags; @Mock private NotificationVisibilityProvider mVisibilityProvider; @Mock private WallpaperManager mWallpaperManager; @Mock private IWallpaperManager mIWallpaperManager; @@ -296,9 +296,10 @@ public class CentralSurfacesImplTest extends SysuiTestCase { private ShadeController mShadeController; private final FakeSystemClock mFakeSystemClock = new FakeSystemClock(); - private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock); - private FakeExecutor mUiBgExecutor = new FakeExecutor(mFakeSystemClock); - private InitController mInitController = new InitController(); + private final FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock); + private final FakeExecutor mUiBgExecutor = new FakeExecutor(mFakeSystemClock); + private final FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags(); + private final InitController mInitController = new InitController(); private final DumpManager mDumpManager = new DumpManager(); @Before @@ -1017,6 +1018,60 @@ public class CentralSurfacesImplTest extends SysuiTestCase { } @Test + public void collapseShade_callsAnimateCollapsePanels_whenExpanded() { + // GIVEN the shade is expanded + mCentralSurfaces.setPanelExpanded(true); + mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE); + + // WHEN collapseShade is called + mCentralSurfaces.collapseShade(); + + // VERIFY that animateCollapsePanels is called + verify(mShadeController).animateCollapsePanels(); + } + + @Test + public void collapseShade_doesNotCallAnimateCollapsePanels_whenCollapsed() { + // GIVEN the shade is collapsed + mCentralSurfaces.setPanelExpanded(false); + mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE); + + // WHEN collapseShade is called + mCentralSurfaces.collapseShade(); + + // VERIFY that animateCollapsePanels is NOT called + verify(mShadeController, never()).animateCollapsePanels(); + } + + @Test + public void collapseShadeForBugReport_callsAnimateCollapsePanels_whenFlagDisabled() { + // GIVEN the shade is expanded & flag enabled + mCentralSurfaces.setPanelExpanded(true); + mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE); + mFeatureFlags.set(Flags.LEAVE_SHADE_OPEN_FOR_BUGREPORT, false); + + // WHEN collapseShadeForBugreport is called + mCentralSurfaces.collapseShadeForBugreport(); + + // VERIFY that animateCollapsePanels is called + verify(mShadeController).animateCollapsePanels(); + } + + @Test + public void collapseShadeForBugReport_doesNotCallAnimateCollapsePanels_whenFlagEnabled() { + // GIVEN the shade is expanded & flag enabled + mCentralSurfaces.setPanelExpanded(true); + mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE); + mFeatureFlags.set(Flags.LEAVE_SHADE_OPEN_FOR_BUGREPORT, true); + + // WHEN collapseShadeForBugreport is called + mCentralSurfaces.collapseShadeForBugreport(); + + // VERIFY that animateCollapsePanels is called + verify(mShadeController, never()).animateCollapsePanels(); + } + + @Test public void deviceStateChange_unfolded_shadeOpen_setsLeaveOpenOnKeyguardHide() { when(mKeyguardStateController.isShowing()).thenReturn(false); setFoldedStates(FOLD_STATE_FOLDED); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerOldImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerOldImplTest.kt index bf432388ad28..eba3b04f3472 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerOldImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerOldImplTest.kt @@ -20,7 +20,6 @@ import android.content.Intent import android.os.UserHandle import android.testing.AndroidTestingRunner import android.testing.TestableLooper -import android.view.View import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.flags.FeatureFlags @@ -34,8 +33,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock -import org.mockito.Mockito.verify import org.mockito.Mockito.`when` +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @@ -91,7 +90,7 @@ class StatusBarUserSwitcherControllerOldImplTest : SysuiTestCase() { fun testStartActivity() { `when`(featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)).thenReturn(false) statusBarUserSwitcherContainer.callOnClick() - verify(userSwitcherDialogController).showDialog(any(View::class.java)) + verify(userSwitcherDialogController).showDialog(any(), any()) `when`(featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)).thenReturn(true) statusBarUserSwitcherContainer.callOnClick() verify(activityStarter).startActivity(any(Intent::class.java), diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeFgsManagerController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeFgsManagerController.kt index 527258579372..c33ce5d9484d 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeFgsManagerController.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeFgsManagerController.kt @@ -16,7 +16,7 @@ package com.android.systemui.qs -import android.view.View +import com.android.systemui.animation.Expandable import com.android.systemui.qs.FgsManagerController.OnDialogDismissedListener import com.android.systemui.qs.FgsManagerController.OnNumberOfPackagesChangedListener import kotlinx.coroutines.flow.MutableStateFlow @@ -54,7 +54,7 @@ class FakeFgsManagerController( override fun init() {} - override fun showDialog(viewLaunchedFrom: View?) {} + override fun showDialog(expandable: Expandable?) {} override fun addOnNumberOfPackagesChangedListener(listener: OnNumberOfPackagesChangedListener) { numRunningPackagesListeners.add(listener) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt index 2a9aeddc9aa8..325da4ead666 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt @@ -57,7 +57,6 @@ import com.android.systemui.statusbar.policy.UserSwitcherController import com.android.systemui.util.mockito.mock import com.android.systemui.util.settings.FakeSettings import com.android.systemui.util.settings.GlobalSettings -import com.android.systemui.util.time.FakeSystemClock import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.test.TestCoroutineDispatcher @@ -68,7 +67,6 @@ import kotlinx.coroutines.test.TestCoroutineDispatcher class FooterActionsTestUtils( private val context: Context, private val testableLooper: TestableLooper, - private val fakeClock: FakeSystemClock = FakeSystemClock(), ) { /** Enable or disable the user switcher in the settings. */ fun setUserSwitcherEnabled(settings: GlobalSettings, enabled: Boolean, userId: Int) { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index fd1fdce4cf77..a55b11838c7b 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -61,6 +61,7 @@ import static android.content.pm.PackageManager.FEATURE_LEANBACK; import static android.content.pm.PackageManager.FEATURE_TELECOM; import static android.content.pm.PackageManager.FEATURE_TELEVISION; import static android.content.pm.PackageManager.MATCH_ALL; +import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -10633,10 +10634,18 @@ public class NotificationManagerService extends SystemService { private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>(); ArrayMap<Pair<ComponentName, Integer>, NotificationListenerFilter> mRequestedNotificationListeners = new ArrayMap<>(); + private final boolean mIsHeadlessSystemUserMode; public NotificationListeners(Context context, Object lock, UserProfiles userProfiles, IPackageManager pm) { + this(context, lock, userProfiles, pm, UserManager.isHeadlessSystemUserMode()); + } + + @VisibleForTesting + public NotificationListeners(Context context, Object lock, UserProfiles userProfiles, + IPackageManager pm, boolean isHeadlessSystemUserMode) { super(context, lock, userProfiles, pm); + this.mIsHeadlessSystemUserMode = isHeadlessSystemUserMode; } @Override @@ -10661,10 +10670,16 @@ public class NotificationManagerService extends SystemService { if (TextUtils.isEmpty(listeners[i])) { continue; } + int packageQueryFlags = MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE; + // In the headless system user mode, packages might not be installed for the + // system user. Match packages for any user since apps can be installed only for + // non-system users and would be considering uninstalled for the system user. + if (mIsHeadlessSystemUserMode) { + packageQueryFlags += MATCH_ANY_USER; + } ArraySet<ComponentName> approvedListeners = - this.queryPackageForServices(listeners[i], - MATCH_DIRECT_BOOT_AWARE - | MATCH_DIRECT_BOOT_UNAWARE, USER_SYSTEM); + this.queryPackageForServices(listeners[i], packageQueryFlags, + USER_SYSTEM); for (int k = 0; k < approvedListeners.size(); k++) { ComponentName cn = approvedListeners.valueAt(k); addDefaultComponentOrPackage(cn.flattenToString()); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java index c5131c8f8c1d..101a5cb49f9b 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenersTest.java @@ -15,6 +15,7 @@ */ package com.android.server.notification; +import static android.content.pm.PackageManager.MATCH_ANY_USER; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; @@ -30,9 +31,11 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.intThat; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -49,6 +52,7 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.pm.VersionedPackage; +import android.content.res.Resources; import android.os.Bundle; import android.os.UserHandle; import android.service.notification.NotificationListenerFilter; @@ -69,6 +73,7 @@ import com.google.common.collect.ImmutableList; import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.internal.util.reflection.FieldSetter; @@ -77,6 +82,7 @@ import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.util.Arrays; import java.util.List; public class NotificationListenersTest extends UiServiceTestCase { @@ -85,6 +91,8 @@ public class NotificationListenersTest extends UiServiceTestCase { private PackageManager mPm; @Mock private IPackageManager miPm; + @Mock + private Resources mResources; @Mock NotificationManagerService mNm; @@ -96,7 +104,8 @@ public class NotificationListenersTest extends UiServiceTestCase { private ComponentName mCn1 = new ComponentName("pkg", "pkg.cmp"); private ComponentName mCn2 = new ComponentName("pkg2", "pkg2.cmp2"); - + private ComponentName mUninstalledComponent = new ComponentName("pkg3", + "pkg3.NotificationListenerService"); @Before public void setUp() throws Exception { @@ -111,7 +120,7 @@ public class NotificationListenersTest extends UiServiceTestCase { @Test public void testReadExtraTag() throws Exception { - String xml = "<" + TAG_REQUESTED_LISTENERS+ ">" + String xml = "<" + TAG_REQUESTED_LISTENERS + ">" + "<listener component=\"" + mCn1.flattenToString() + "\" user=\"0\">" + "<allowed types=\"7\" />" + "</listener>" @@ -131,11 +140,55 @@ public class NotificationListenersTest extends UiServiceTestCase { } @Test + public void loadDefaultsFromConfig_forHeadlessSystemUser_loadUninstalled() throws Exception { + // setup with headless system user mode + mListeners = spy(mNm.new NotificationListeners( + mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm, + /* isHeadlessSystemUserMode= */ true)); + mockDefaultListenerConfigForUninstalledComponent(mUninstalledComponent); + + mListeners.loadDefaultsFromConfig(); + + assertThat(mListeners.getDefaultComponents()).contains(mUninstalledComponent); + } + + @Test + public void loadDefaultsFromConfig_forNonHeadlessSystemUser_ignoreUninstalled() + throws Exception { + // setup without headless system user mode + mListeners = spy(mNm.new NotificationListeners( + mContext, new Object(), mock(ManagedServices.UserProfiles.class), miPm, + /* isHeadlessSystemUserMode= */ false)); + mockDefaultListenerConfigForUninstalledComponent(mUninstalledComponent); + + mListeners.loadDefaultsFromConfig(); + + assertThat(mListeners.getDefaultComponents()).doesNotContain(mUninstalledComponent); + } + + private void mockDefaultListenerConfigForUninstalledComponent(ComponentName componentName) { + ArraySet<ComponentName> components = new ArraySet<>(Arrays.asList(componentName)); + when(mResources + .getString( + com.android.internal.R.string.config_defaultListenerAccessPackages)) + .thenReturn(componentName.getPackageName()); + when(mContext.getResources()).thenReturn(mResources); + doReturn(components).when(mListeners).queryPackageForServices( + eq(componentName.getPackageName()), + intThat(hasIntBitFlag(MATCH_ANY_USER)), + anyInt()); + } + + public static ArgumentMatcher<Integer> hasIntBitFlag(int flag) { + return arg -> arg != null && ((arg & flag) == flag); + } + + @Test public void testWriteExtraTag() throws Exception { NotificationListenerFilter nlf = new NotificationListenerFilter(7, new ArraySet<>()); VersionedPackage a1 = new VersionedPackage("pkg1", 243); NotificationListenerFilter nlf2 = - new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[] {a1})); + new NotificationListenerFilter(4, new ArraySet<>(new VersionedPackage[]{a1})); mListeners.setNotificationListenerFilter(Pair.create(mCn1, 0), nlf); mListeners.setNotificationListenerFilter(Pair.create(mCn2, 10), nlf2); |