Merge "Register VolumeDialogControllerImpl with DumpManager." into tm-qpr-dev
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e820733..f320b74 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4453,6 +4453,10 @@
          * <p>Apps targeting {@link Build.VERSION_CODES#Q} and above will have to request
          * a permission ({@link android.Manifest.permission#USE_FULL_SCREEN_INTENT}) in order to
          * use full screen intents.</p>
+         * <p>
+         * To be launched as a full screen intent, the notification must also be posted to a
+         * channel with importance level set to IMPORTANCE_HIGH or higher.
+         * </p>
          *
          * @param intent The pending intent to launch.
          * @param highPriority Passing true will cause this notification to be sent
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 9e87037..90e92db 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -159,8 +159,9 @@
      *
      * <li> For a SurfaceView output surface, the timestamp base is {@link
      * #TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED}. The timestamp is overridden with choreographer
-     * pulses from the display subsystem for smoother display of camera frames. The timestamp
-     * is roughly in the same time base as {@link android.os.SystemClock#uptimeMillis}.</li>
+     * pulses from the display subsystem for smoother display of camera frames when the camera
+     * device runs in fixed frame rate. The timestamp is roughly in the same time base as
+     * {@link android.os.SystemClock#uptimeMillis}.</li>
      * <li> For an output surface of MediaRecorder, MediaCodec, or ImageReader with {@link
      * android.hardware.HardwareBuffer#USAGE_VIDEO_ENCODE} usge flag, the timestamp base is
      * {@link #TIMESTAMP_BASE_MONOTONIC}, which is roughly the same time base as
@@ -231,7 +232,8 @@
      *
      * <p>The timestamp of the output images are overridden with choreographer pulses from the
      * display subsystem for smoother display of camera frames. An output target of SurfaceView
-     * uses this time base by default.</p>
+     * uses this time base by default. Note that the timestamp override is done for fixed camera
+     * frame rate only.</p>
      *
      * <p>This timestamp base isn't applicable to SurfaceTexture targets. SurfaceTexture's
      * {@link android.graphics.SurfaceTexture#updateTexImage updateTexImage} function always
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 7a9991b..8fb09fc 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Gee eenmalige toegang"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Moenie toelaat nie"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Toestelloglêers teken aan wat op jou toestel gebeur. Programme kan hierdie loglêers gebruik om kwessies op te spoor en reg te stel.\n\nSommige loglêers bevat dalk sensitiewe inligting en daarom moet jy toegang tot alle toestelloglêers net gee aan programme wat jy vertrou. \n\nAs jy nie vir hierdie program toegang tot alle toestelloglêers gee nie, het die program steeds toegang tot eie loglêers. Jou toestelvervaardiger het dalk steeds toegang tot sommige loglêers of inligting op jou toestel."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Toestelloglêers teken aan wat op jou toestel gebeur. Programme kan hierdie loglêers gebruik om kwessies op te spoor en reg te stel.\n\nSommige loglêers bevat dalk sensitiewe inligting, en daarom moet jy toegang tot alle toestelloglêers net gee aan programme wat jy vertrou. \n\nHierdie program het steeds toegang tot eie loglêers as jy nie vir hierdie program toegang tot alle toestelloglêers gee nie. Jou toestelvervaardiger het dalk steeds toegang tot sommige loglêers of inligting op jou toestel.\n\nKom meer te wete by g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Moenie weer wys nie"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wil <xliff:g id="APP_2">%2$s</xliff:g>-skyfies wys"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Wysig"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index d62800f..bc6aa16 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Birdəfəlik girişə icazə verin"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"İcazə verməyin"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Cihaz qeydləri cihazınızda baş verənləri qeyd edir. Tətbiqlər problemləri tapmaq və həll etmək üçün bu qeydlərdən istifadə edə bilər.\n\nBəzi qeydlərdə həssas məlumatlar ola bilər, ona görə də yalnız etibar etdiyiniz tətbiqlərin bütün cihaz qeydlərinə giriş etməsinə icazə verin. \n\nBu tətbiqin bütün cihaz qeydlərinə girişinə icazə verməsəniz, o, hələ də öz qeydlərinə giriş edə bilər. Cihaz istehsalçınız hələ də cihazınızda bəzi qeydlərə və ya məlumatlara giriş edə bilər."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Cihaz qeydləri cihazınızda baş verənləri qeyd edir. Tətbiqlər problemləri tapmaq və həll etmək üçün bu qeydlərdən istifadə edə bilər.\n\nBəzi qeydlərdə həssas məlumatlar ola bilər, ona görə də yalnız etibar etdiyiniz tətbiqlərin bütün cihaz qeydlərinə giriş etməsinə icazə verin. \n\nBu tətbiqin bütün cihaz qeydlərinə girişinə icazə verməsəniz, o, hələ də öz qeydlərinə giriş edə bilər. Cihaz istehsalçınız hələ də cihazınızda bəzi qeydlərə və ya məlumatlara giriş edə bilər.\n\nƏtraflı məlumat: g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Daha göstərməyin"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g> tətbiqindən bölmələr göstərmək istəyir"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Redaktə edin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 0d6812d..d0e2a3c 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -2052,8 +2052,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Dozvoli jednokratan pristup"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne dozvoli"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Evidencije uređaja registruju šta se dešava na uređaju. Aplikacije mogu da koriste te evidencije da bi pronašle i rešile probleme.\n\nNeke evidencije mogu da sadrže osetljive informacije, pa pristup svim evidencijama uređaja treba da dozvoljavate samo aplikacijama u koje imate poverenja. \n\nAko ne dozvolite ovoj aplikaciji da pristupa svim evidencijama uređaja, ona i dalje može da pristupa sopstvenim evidencijama. Proizvođač uređaja će možda i dalje moći da pristupa nekim evidencijama ili informacijama na uređaju."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Evidencije uređaja registruju šta se dešava na uređaju. Aplikacije mogu da koriste te evidencije da bi pronašle i rešile probleme.\n\nNeke evidencije mogu da sadrže osetljive informacije, pa pristup svim evidencijama uređaja treba da dozvoljavate samo aplikacijama u koje imate poverenja. \n\nAko ne dozvolite ovoj aplikaciji da pristupa svim evidencijama uređaja, ona i dalje može da pristupa sopstvenim evidencijama. Proizvođač uređaja će možda i dalje moći da pristupa nekim evidencijama ili informacijama na uređaju.\n\nSaznajte više na g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi da prikazuje isečke iz aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Izmeni"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index a3e3db9..b3e4fc3 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -195,7 +195,7 @@
     <string name="network_logging_notification_text" msgid="1327373071132562512">"Ваша арганізацыя кіруе гэтай прыладай і можа сачыць за сеткавым трафікам. Дакраніцеся для атрымання дадатковай інфармацыі."</string>
     <string name="location_changed_notification_title" msgid="3620158742816699316">"Праграмы могуць атрымліваць даныя пра ваша месцазнаходжанне"</string>
     <string name="location_changed_notification_text" msgid="7158423339982706912">"Каб даведацца больш, звярніцеся да ІТ-адміністратара"</string>
-    <string name="geofencing_service" msgid="3826902410740315456">"Служба вызначэння геаперыметра"</string>
+    <string name="geofencing_service" msgid="3826902410740315456">"Сэрвіс геазаніравання"</string>
     <string name="country_detector" msgid="7023275114706088854">"Дэтэктар краіны"</string>
     <string name="location_service" msgid="2439187616018455546">"Служба геалакацыі"</string>
     <string name="gnss_service" msgid="8907781262179951385">"Служба GNSS"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index affa2b7..6da6267 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"এককালীন অ্যাক্সেসের অনুমতি দিন"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"অনুমতি দেবেন না"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ডিভাইস লগে আপনার ডিভাইসে করা অ্যাক্টিভিটি রেকর্ড করা হয়। অ্যাপ সমস্যা খুঁজে তা সমাধান করতে এইসব লগ ব্যবহার করতে পারে।\n\nকিছু লগে সংবেদনশীল তথ্য থাকতে পারে, তাই বিশ্বাস করেন শুধুমাত্র এমন অ্যাপকেই সব ডিভাইসের লগ অ্যাক্সেসের অনুমতি দিন। \n\nআপনি এই অ্যাপকে ডিভাইসের সব লগ অ্যাক্সেস করার অনুমতি না দিলেও, এটি নিজের লগ অ্যাক্সেস করতে পারবে। ডিভাইস প্রস্তুতকারকও আপনার ডিভাইসের কিছু লগ বা তথ্য হয়ত অ্যাক্সেস করতে পারবে।"</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"ডিভাইস লগে আপনার ডিভাইসে করা অ্যাক্টিভিটি রেকর্ড করা হয়। অ্যাপ, সমস্যা খুঁজে তা সমাধান করতে এইসব লগ ব্যবহার করতে পারে।\n\nকিছু লগে সংবেদনশীল তথ্য থাকতে পারে, তাই বিশ্বাস করেন শুধুমাত্র এমন অ্যাপকেই ডিভাইসের সব লগ অ্যাক্সেসের অনুমতি দিন। \n\nআপনি এই অ্যাপকে ডিভাইসের সব লগ অ্যাক্সেস করার অনুমতি না দিলেও, এটি নিজের লগ অ্যাক্সেস করতে পারবে। ডিভাইস প্রস্তুতকারক এখনও আপনার ডিভাইসের কিছু লগ বা তথ্য হয়ত অ্যাক্সেস করতে পারবে।\n\ng.co/android/devicelogs লিঙ্ক থেকে আরও জানুন।"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"আর দেখতে চাই না"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> অ্যাপটি <xliff:g id="APP_2">%2$s</xliff:g> এর অংশ দেখাতে চায়"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"এডিট করুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index f59c543..e597330 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -2052,8 +2052,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Dozvoli jednokratan pristup"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nemoj dozvoliti"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Zapisnici uređaja bilježe šta se dešava na uređaju. Aplikacije mogu koristiti te zapisnike da pronađu i isprave probleme.\n\nNeki zapisnici mogu sadržavati osjetljive podatke, zato pristup svim zapisnicima uređaja dozvolite samo aplikacijama kojima vjerujete. \n\nAko ne dozvolite ovoj aplikaciji da pristupa svim zapisnicima uređaja, ona i dalje može pristupati svojim zapisnicima. Proizvođač uređaja će možda i dalje biti u stanju pristupiti nekim zapisnicima ili podacima na uređaju."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Zapisnici uređaja bilježe šta se dešava na uređaju. Aplikacije mogu koristiti te zapisnike da pronađu i riješe probleme.\n\nNeki zapisnici mogu sadržavati osjetljive podatke. Zbog toga pristup svim zapisnicima uređaja dozvolite samo aplikacijama koje smatrate pouzdanima. \n\nAko ne dozvolite ovoj aplikaciji da pristupa svim zapisnicima uređaja, ona i dalje može pristupati svojim zapisnicima. Proizvođač uređaja će možda i dalje moći pristupiti nekim zapisnicima ili podacima na uređaju.\n\nSaznajte više na g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Aplikacija <xliff:g id="APP_0">%1$s</xliff:g> želi prikazati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 80af569..b04d8c9 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1949,9 +1949,9 @@
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"Android TV-indstillingerne er ikke tilgængelige"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"Tabletindstillingerne er ikke tilgængelige"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"Telefonindstillingerne er ikke tilgængelige"</string>
-    <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Du har ikke adgang til denne app på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din Android TV-enhed i stedet."</string>
-    <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Du har ikke adgang til denne app på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din tablet i stedet."</string>
-    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Du har ikke adgang til denne app på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din telefon i stedet."</string>
+    <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Dette er ikke tilgængeligt på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din Android TV-enhed i stedet."</string>
+    <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Dette er ikke tilgængeligt på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din tablet i stedet."</string>
+    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Dette er ikke tilgængeligt på din <xliff:g id="DEVICE">%1$s</xliff:g> på nuværende tidspunkt. Prøv på din telefon i stedet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Denne app anmoder om yderligere sikkerhed. Prøv på din Android TV-enhed i stedet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Denne app anmoder om yderligere sikkerhed. Prøv på din tablet i stedet."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Denne app anmoder om yderligere sikkerhed. Prøv på din telefon i stedet."</string>
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Tillad engangsadgang"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tillad ikke"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Enhedslogs registrerer, hvad der sker på din enhed. Apps kan bruge disse logs til at finde og løse problemer.\n\nNogle logs kan indeholde følsomme oplysninger, så giv kun apps, du har tillid til, adgang til alle enhedslogs. \n\nSelvom du ikke giver denne app adgang til alle enhedslogs, kan den stadig tilgå sine egne logs. Producenten af din enhed kan muligvis fortsat tilgå visse logs eller oplysninger på din enhed."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Enhedslogs registrerer, hvad der sker på din enhed. Apps kan bruge disse logs til at finde og løse problemer.\n\nNogle logs kan indeholde følsomme oplysninger, så giv kun apps, du har tillid til, adgang til alle enhedslogs. \n\nSelvom du ikke giver denne app adgang til alle enhedslogs, kan den stadig tilgå sine egne logs. Producenten af din enhed kan muligvis fortsat tilgå visse logs eller oplysninger på din enhed.\n\nFå flere oplysninger på g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Vis ikke igen"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> anmoder om tilladelse til at vise eksempler fra <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Rediger"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 1dd2e65..1fcf94e 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Να επιτρέπεται η πρόσβαση για μία φορά"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Να μην επιτραπεί"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Τα αρχεία καταγραφής συσκευής καταγράφουν ό,τι συμβαίνει στη συσκευή σας. Οι εφαρμογές μπορούν να χρησιμοποιούν αυτά τα αρχεία καταγραφής για να εντοπίζουν και να διορθώνουν ζητήματα.\n\nΟρισμένα αρχεία καταγραφής ενδέχεται να περιέχουν ευαίσθητες πληροφορίες. Ως εκ τούτου, επιτρέψτε την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής μόνο στις εφαρμογές που εμπιστεύεστε. \n\nΕάν δεν επιτρέψετε σε αυτήν την εφαρμογή την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής, η εφαρμογή εξακολουθεί να έχει πρόσβαση στα δικά της αρχεία καταγραφής. Ο κατασκευαστής της συσκευής σας ενδέχεται να εξακολουθεί να έχει πρόσβαση σε ορισμένα αρχεία καταγραφής ή ορισμένες πληροφορίες στη συσκευή σας."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Τα αρχεία καταγραφής συσκευής καταγράφουν ό,τι συμβαίνει στη συσκευή σας. Οι εφαρμογές μπορούν να χρησιμοποιούν αυτά τα αρχεία καταγραφής για να εντοπίζουν και να διορθώνουν ζητήματα.\n\nΟρισμένα αρχεία καταγραφής ενδέχεται να περιέχουν ευαίσθητες πληροφορίες. Ως εκ τούτου, επιτρέψτε την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής μόνο στις εφαρμογές που εμπιστεύεστε. \n\nΕάν δεν επιτρέψετε σε αυτήν την εφαρμογή την πρόσβαση σε όλα τα αρχεία καταγραφής συσκευής, η εφαρμογή εξακολουθεί να έχει πρόσβαση στα δικά της αρχεία καταγραφής. Ο κατασκευαστής της συσκευής σας ενδέχεται να εξακολουθεί να έχει πρόσβαση σε ορισμένα αρχεία καταγραφής ή σε πληροφορίες στη συσκευή σας.\n\nΜάθετε περισσότερα στη διεύθυνση g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Να μην εμφανισ. ξανά"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Η εφαρμογή <xliff:g id="APP_0">%1$s</xliff:g> θέλει να εμφανίζει τμήματα της εφαρμογής <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Επεξεργασία"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index cd10c3b..bde1fe0 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device.\n\nLearn more at g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index ef16aef..cbed459 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device.\n\nLearn more at g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 759c2f6..fcd40c5 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device.\n\nLearn more at g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 9d1fc96..e583cef 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Allow one-time access"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Don’t allow"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Device logs record what happens on your device. Apps can use these logs to find and fix issues.\n\nSome logs may contain sensitive info, so only allow apps that you trust to access all device logs. \n\nIf you don’t allow this app to access all device logs, it can still access its own logs. Your device manufacturer may still be able to access some logs or info on your device.\n\nLearn more at g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Don’t show again"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wants to show <xliff:g id="APP_2">%2$s</xliff:g> slices"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index e58e74d..2a3f916 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -2052,8 +2052,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir acceso por única vez"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"No permitir"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Los registros del dispositivo permiten documentar lo que sucede en él. Las apps pueden usar estos registros para encontrar y solucionar problemas.\n\nEs posible que algunos registros del dispositivo contengan información sensible, por lo que solo debes permitir que accedan a todos ellos las apps que sean de tu confianza. \n\nSi no permites que esta app acceda a todos los registros del dispositivo, aún puede acceder a sus propios registros. Además, es posible que el fabricante del dispositivo acceda a algunos registros o información en tu dispositivo."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Los registros del dispositivo permiten documentar lo que sucede en él. Las apps pueden usar estos registros para encontrar y solucionar problemas.\n\nEs posible que algunos registros del dispositivo contengan información sensible, por lo que solo debes permitir que accedan a todos los registros las apps que sean de tu confianza. \n\nTen en cuenta que la app puede acceder a sus propios registros incluso si no permites que acceda a todos los registros del dispositivo. También es posible que el fabricante del dispositivo acceda a algunos registros o información en tu dispositivo.\n\nObtén más información en g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"No volver a mostrar"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quiere mostrar fragmentos de <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 1ed44c8..e79cacb 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -2291,7 +2291,7 @@
     <string name="notification_content_abusive_bg_apps" msgid="5296898075922695259">"Rakendus <xliff:g id="APP">%1$s</xliff:g> töötab taustal. Puudutage akukasutuse haldamiseks."</string>
     <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"<xliff:g id="APP">%1$s</xliff:g> võib aku tööiga mõjutada. Puudutage aktiivsete rakenduste ülevaatamiseks."</string>
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Vaadake aktiivseid rakendusi"</string>
-    <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse telefoni kaamerale juurde"</string>
+    <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse telefoni kaamerale juurde."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse tahvelarvuti kaamerale juurde"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Sellele ei pääse voogesituse ajal juurde. Proovige juurde pääseda oma telefonis."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Süsteemi vaikeseade"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 12fc578..067388d 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -2052,8 +2052,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Autoriser un accès unique"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ne pas autoriser"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Les journaux de l\'appareil enregistrent ce qui se passe sur celui-ci. Les applications peuvent utiliser ces journaux pour trouver et résoudre des problèmes.\n\nCertains journaux peuvent contenir des renseignements confidentiels. N\'autorisez donc que les applications auxquelles vous faites confiance puisque celles-ci pourront accéder à l\'ensemble des journaux de l\'appareil. \n\nMême si vous n\'autorisez pas cette application à accéder à l\'ensemble des journaux de l\'appareil, elle aura toujours accès à ses propres journaux. Le fabricant de votre appareil pourrait toujours être en mesure d\'accéder à certains journaux ou renseignements sur votre appareil."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Les journaux de l\'appareil enregistrent ce qui se passe sur celui-ci. Les applications peuvent utiliser ces journaux pour trouver et résoudre des problèmes.\n\nCertains journaux peuvent contenir des renseignements confidentiels. N\'autorisez donc que les applications auxquelles vous faites confiance puisque celles-ci pourront accéder à l\'ensemble des journaux de l\'appareil. \n\nMême si vous n\'autorisez pas cette application à accéder à l\'ensemble des journaux de l\'appareil, elle aura toujours accès à ses propres journaux. Le fabricant de votre appareil pourrait toujours être en mesure d\'accéder à certains journaux ou renseignements sur votre appareil.\n\nPour en savoir plus, consultez la page g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne plus afficher"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> souhaite afficher <xliff:g id="APP_2">%2$s</xliff:g> tranches"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Modifier"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 96246a6..fa3784fa 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"એક-વખતના ઍક્સેસની મંજૂરી આપો"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"મંજૂરી આપશો નહીં"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"તમારા ડિવાઇસ પર થતી કામગીરીને ડિવાઇસ લૉગ રેકોર્ડ કરે છે. ઍપ આ લૉગનો ઉપયોગ સમસ્યાઓ શોધી તેનું નિરાકરણ કરવા માટે કરી શકે છે.\n\nઅમુક લૉગમાં સંવેદનશીલ માહિતી હોઈ શકે, આથી ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી માત્ર તમારી વિશ્વાસપાત્ર ઍપને જ આપો. \n\nજો તમે આ ઍપને ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી ન આપો, તો પણ તે તેના પોતાના લૉગ ઍક્સેસ કરી શકે છે. તમારા ડિવાઇસના નિર્માતા હજુ પણ કદાચ તમારા ડિવાઇસ પર અમુક લૉગ અથવા માહિતી ઍક્સેસ કરી શકે છે."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"તમારા ડિવાઇસ પર થતી કામગીરીને ડિવાઇસ લૉગ રેકોર્ડ કરે છે. ઍપ આ લૉગનો ઉપયોગ સમસ્યાઓ શોધી તેનું નિરાકરણ કરવા માટે કરી શકે છે.\n\nઅમુક લૉગમાં સંવેદનશીલ માહિતી હોઈ શકે, આથી ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી માત્ર તમારી વિશ્વાસપાત્ર ઍપને જ આપો. \n\nજો તમે આ ઍપને ડિવાઇસનો બધો લૉગ ઍક્સેસ કરવાની મંજૂરી ન આપો, તો પણ તે તેના પોતાના લૉગ ઍક્સેસ કરી શકે છે. તમારા ડિવાઇસના નિર્માતા હજુ પણ કદાચ તમારા ડિવાઇસ પર અમુક લૉગ અથવા માહિતી ઍક્સેસ કરી શકે છે.\n\ng.co/android/devicelogs પર વધુ જાણો."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ફરીથી બતાવશો નહીં"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>એ <xliff:g id="APP_2">%2$s</xliff:g> સ્લાઇસ બતાવવા માગે છે"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ફેરફાર કરો"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index c7fc1ef..fb95a1f 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -2052,8 +2052,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Omogući jednokratni pristup"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nemoj dopustiti"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"U zapisnicima uređaja bilježi se što se događa na uređaju. Aplikacije mogu koristiti te zapisnike kako bi pronašle i riješile poteškoće.\n\nNeki zapisnici mogu sadržavati osjetljive podatke, pa pristup svim zapisnicima uređaja odobrite samo pouzdanim aplikacijama. \n\nAko ne dopustite ovoj aplikaciji da pristupa svim zapisnicima uređaja, ona i dalje može pristupati svojim zapisnicima. Proizvođač vašeg uređaja i dalje može pristupati nekim zapisnicima ili podacima na vašem uređaju."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"U zapisnicima uređaja bilježi se što se događa na uređaju. Aplikacije mogu koristiti te zapisnike kako bi pronašle i riješile poteškoće.\n\nNeki zapisnici mogu sadržavati osjetljive podatke, pa pristup svim zapisnicima uređaja odobrite samo pouzdanim aplikacijama. \n\nAko ne dopustite ovoj aplikaciji da pristupa svim zapisnicima uređaja, ona i dalje može pristupati svojim zapisnicima. Proizvođač vašeg uređaja i dalje može pristupati nekim zapisnicima ili podacima na vašem uređaju.\n\nSaznajte više na g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne prikazuj ponovo"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> želi prikazivati isječke aplikacije <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Uredi"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index b6c40eb..6c700dd1 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Egyszeri hozzáférés engedélyezése"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Tiltás"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Az eszköznaplók rögzítik, hogy mi történik az eszközén. Az alkalmazások ezeket a naplókat használhatják a problémák megkeresésére és kijavítására.\n\nBizonyos naplók bizalmas adatokat is tartalmazhatnak, ezért csak olyan alkalmazások számára engedélyezze az összes eszköznaplóhoz való hozzáférést, amelyekben megbízik. \n\nHa nem engedélyezi ennek az alkalmazásnak, hogy hozzáférjen az összes eszköznaplójához, az app továbbra is hozzáférhet a saját naplóihoz. Előfordulhat, hogy az eszköz gyártója továbbra is hozzáfér az eszközön található bizonyos naplókhoz és adatokhoz."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Az eszköznaplók rögzítik, hogy mi történik az eszközén. Az alkalmazások ezeket a naplókat használhatják a problémák megkeresésére és kijavítására.\n\nBizonyos naplók bizalmas adatokat is tartalmazhatnak, ezért csak olyan alkalmazások számára engedélyezze az összes eszköznaplóhoz való hozzáférést, amelyekben megbízik. \n\nHa nem engedélyezi ennek az alkalmazásnak, hogy hozzáférjen az összes eszköznaplójához, az app továbbra is hozzáférhet a saját naplóihoz. Előfordulhat, hogy az eszköz gyártója továbbra is hozzáfér az eszközön található bizonyos naplókhoz és adatokhoz.\n\nTovábbi információ: g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ne jelenjen meg újra"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"A(z) <xliff:g id="APP_0">%1$s</xliff:g> alkalmazás részleteket szeretne megjeleníteni a(z) <xliff:g id="APP_2">%2$s</xliff:g> alkalmazásból"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Szerkesztés"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9268cac..0e32d33 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -2052,8 +2052,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Consenti accesso una tantum"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Non consentire"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"I log del dispositivo registrano tutto ciò che succede sul tuo dispositivo. Le app possono usare questi log per individuare problemi e correggerli.\n\nAlcuni log potrebbero contenere informazioni sensibili, quindi concedi l\'accesso a tutti i log del dispositivo soltanto alle app attendibili. \n\nSe le neghi l\'accesso a tutti i log del dispositivo, questa app può comunque accedere ai propri log. Il produttore del tuo dispositivo potrebbe essere comunque in grado di accedere ad alcuni log o informazioni sul dispositivo."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"I log del dispositivo registrano tutto ciò che succede sul tuo dispositivo. Le app possono usare questi log per individuare problemi e correggerli.\n\nAlcuni log potrebbero contenere informazioni sensibili, quindi concedi l\'accesso a tutti i log del dispositivo soltanto alle app attendibili. \n\nSe le neghi l\'accesso a tutti i log del dispositivo, questa app può comunque accedere ai propri log. Il produttore del tuo dispositivo potrebbe essere comunque in grado di accedere ad alcuni log o informazioni sul dispositivo.\n\nScopri di più all\'indirizzo g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Non mostrare più"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"L\'app <xliff:g id="APP_0">%1$s</xliff:g> vuole mostrare porzioni dell\'app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Modifica"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index cfc1fb0..57176a6 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1953,13 +1953,13 @@
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"ההגדרות של הטלפון לא זמינות"</string>
     <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"‏אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות במכשיר Android TV."</string>
     <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות בטאבלט."</string>
-    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, יש לנסות בטלפון."</string>
+    <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"אי אפשר לגשת לאפליקציה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g> כרגע. במקום זאת, אפשר לנסות בטלפון."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"‏האפליקציה הזו מבקשת אמצעי אבטחה נוסף. במקום זאת, יש לנסות במכשיר Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"האפליקציה הזו מבקשת אמצעי אבטחה נוסף. במקום זאת, יש לנסות בטאבלט."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"האפליקציה הזו מבקשת אמצעי אבטחה נוסף. במקום זאת, יש לנסות בטלפון."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"‏אי אפשר לגשת להגדרה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g>. במקום זאת, יש לנסות במכשיר Android TV."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"אי אפשר לגשת להגדרה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g>. במקום זאת, יש לנסות בטאבלט."</string>
-    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"אי אפשר לגשת להגדרה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g>. במקום זאת, יש לנסות בטלפון."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"אי אפשר לגשת להגדרה הזו במכשיר <xliff:g id="DEVICE">%1$s</xliff:g>. במקום זאת, אפשר לנסות בטלפון."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"‏האפליקציה הזו עוצבה לגרסה ישנה יותר של Android וייתכן שלא תפעל כראוי. ניתן לבדוק אם יש עדכונים או ליצור קשר עם המפתח."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"יש עדכון חדש?"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"יש לך הודעות חדשות"</string>
@@ -2295,6 +2295,6 @@
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"כדאי לבדוק את האפליקציות הפעילות"</string>
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"לא ניתן לגשת למצלמה של הטלפון מה‑<xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"לא ניתן לגשת למצלמה של הטאבלט מה‑<xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <string name="vdm_secure_window" msgid="161700398158812314">"אי אפשר לגשת לתוכן המאובטח הזה בזמן סטרימינג. במקום זאת, יש לנסות בטלפון."</string>
+    <string name="vdm_secure_window" msgid="161700398158812314">"אי אפשר לגשת לתוכן המאובטח הזה בזמן סטרימינג. במקום זאת, אפשר לנסות בטלפון."</string>
     <string name="system_locale_title" msgid="711882686834677268">"ברירת המחדל של המערכת"</string>
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 07e8be9..c48d37c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"1 回限りのアクセスを許可"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"許可しない"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"デバイスのログに、このデバイスで発生したことが記録されます。アプリは問題を検出、修正するためにこれらのログを使用することができます。\n\nログによっては機密性の高い情報が含まれている可能性があるため、すべてのデバイスログへのアクセスは信頼できるアプリにのみ許可してください。\n\nすべてのデバイスログへのアクセスを許可しなかった場合も、このアプリはアプリ独自のログにアクセスできます。また、デバイスのメーカーもデバイスの一部のログや情報にアクセスできる可能性があります。"</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"デバイスのログに、このデバイスで発生したことが記録されます。アプリは問題を検出、修正するためにこれらのログを使用することができます。\n\nログによっては機密性の高い情報が含まれている可能性があるため、すべてのデバイスログへのアクセスは信頼できるアプリにのみ許可してください。\n\nすべてのデバイスログへのアクセスを許可しなかった場合でも、このアプリはアプリ独自のログにアクセスできます。また、デバイスの製造メーカーもデバイスの一部のログや情報にアクセスできる可能性があります。\n\n詳しくは、g.co/android/devicelogs をご覧ください。"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"次回から表示しない"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"「<xliff:g id="APP_0">%1$s</xliff:g>」が「<xliff:g id="APP_2">%2$s</xliff:g>」のスライスの表示をリクエストしています"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"編集"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index e09255f..9cc6ae4 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ერთჯერადი წვდომის დაშვება"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"არ დაიშვას"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"მოწყობილობის ჟურნალში იწერება, რა ხდება ამ მოწყობილობაზე. აპებს შეუძლია ამ ჟურნალების გამოყენება პრობლემების აღმოსაჩენად და მოსაგვარებლად.\n\nზოგი ჟურნალი შეიძლება სენსიტიური ინფორმაციის მატარებელი იყოს, ამიტომაც მოწყობილობის ყველა ჟურნალზე წვდომა მხოლოდ სანდო აპებს მიანიჭეთ. \n\nთუ ამ აპს მოწყობილობის ყველა ჟურნალზე წვდომას არ მიანიჭებთ, მას მაინც ექნება წვდომა თქვენს ჟურნალებზე. თქვენი მოწყობილობის მწარმოებელს მაინც შეეძლება თქვენი მოწყობილობის ზოგიერთ ჟურნალსა თუ ინფორმაციაზე წვდომა."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"მოწყობილობის ჟურნალში იწერება, რა ხდება ამ მოწყობილობაზე. აპებს შეუძლია ამ ჟურნალების გამოყენება პრობლემების აღმოსაჩენად და მოსაგვარებლად.\n\nზოგი ჟურნალი შეიძლება სენსიტიური ინფორმაციის მატარებელი იყოს, ამიტომაც მოწყობილობის ყველა ჟურნალზე წვდომა მხოლოდ სანდო აპებს მიანიჭეთ. \n\nთუ ამ აპს მოწყობილობის ყველა ჟურნალზე წვდომას არ მიანიჭებთ, მას მაინც ექნება წვდომა საკუთარ ჟურნალებზე. თქვენი მოწყობილობის მწარმოებელს მაინც შეეძლება თქვენი მოწყობილობის ზოგიერთ ჟურნალსა თუ ინფორმაციაზე წვდომა.\n\n შეიტყვეთ მეტი g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"აღარ გამოჩნდეს"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>-ს სურს, გაჩვენოთ <xliff:g id="APP_2">%2$s</xliff:g>-ის ფრაგმენტები"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"რედაქტირება"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index afb98ba..0c7d4b1 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ಒಂದು ಬಾರಿಯ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಿ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ಅನುಮತಿಸಬೇಡಿ"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಸಾಧನದ ಲಾಗ್‌ಗಳು ರೆಕಾರ್ಡ್ ಮಾಡುತ್ತವೆ. ಸಮಸ್ಯೆಗಳನ್ನು ಪತ್ತೆಹಚ್ಚಲು ಮತ್ತು ಪರಿಹರಿಸಲು ಆ್ಯಪ್‌ಗಳು ಈ ಲಾಗ್ ಅನ್ನು ಬಳಸಬಹುದು.\n\nಕೆಲವು ಲಾಗ್‌ಗಳು ಸೂಕ್ಷ್ಮ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರಬಹುದು, ಆದ್ದರಿಂದ ನಿಮ್ಮ ವಿಶ್ವಾಸಾರ್ಹ ಆ್ಯಪ್‌ಗಳಿಗೆ ಮಾತ್ರ ಸಾಧನದ ಎಲ್ಲಾ ಲಾಗ್‌ಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಿ. \n\nಎಲ್ಲಾ ಸಾಧನ ಲಾಗ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ನೀವು ಈ ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸದಿದ್ದರೆ, ಅದು ಆಗಲೂ ತನ್ನದೇ ಆದ ಲಾಗ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಬಹುದು. ನಿಮ್ಮ ಸಾಧನ ತಯಾರಕರಿಗೆ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕೆಲವು ಲಾಗ್‌ಗಳು ಅಥವಾ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು ಈಗಲೂ ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕಾರ್ಯಾಚರಣೆಗಳನ್ನು ಸಾಧನದ ಲಾಗ್‌ಗಳು ರೆಕಾರ್ಡ್ ಮಾಡುತ್ತವೆ. ಸಮಸ್ಯೆಗಳನ್ನು ಪತ್ತೆಹಚ್ಚಲು ಮತ್ತು ಪರಿಹರಿಸಲು ಆ್ಯಪ್‌ಗಳು ಈ ಲಾಗ್ ಅನ್ನು ಬಳಸಬಹುದು.\n\nಕೆಲವು ಲಾಗ್‌ಗಳು ಸೂಕ್ಷ್ಮ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರಬಹುದು, ಆದ್ದರಿಂದ ನಿಮ್ಮ ವಿಶ್ವಾಸಾರ್ಹ ಆ್ಯಪ್‌ಗಳಿಗೆ ಮಾತ್ರ ಸಾಧನದ ಎಲ್ಲಾ ಲಾಗ್‌ಗಳಿಗೆ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಿ. \n\nಎಲ್ಲಾ ಸಾಧನ ಲಾಗ್‌ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ನೀವು ಈ ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸದಿದ್ದರೆ, ಅದು ಆಗಲೂ ತನ್ನದೇ ಆದ ಲಾಗ್‌ಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಬಹುದು. ಹಾಗಿದ್ದರೂ, ನಿಮ್ಮ ಸಾಧನ ತಯಾರಕರಿಗೆ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿನ ಕೆಲವು ಲಾಗ್‌ಗಳು ಅಥವಾ ಮಾಹಿತಿಯನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗಬಹುದು.\n\ng.co/android/devicelogs ನಲ್ಲಿ ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡಿ"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> ಸ್ಲೈಸ್‌ಗಳನ್ನು <xliff:g id="APP_0">%1$s</xliff:g> ತೋರಿಸಲು ಬಯಸಿದೆ"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ಎಡಿಟ್"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index e5e18cc..81ec5b7 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ອະນຸຍາດການເຂົ້າເຖິງແບບເທື່ອດຽວ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ບໍ່ອະນຸຍາດ"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ບັນທຶກອຸປະກອນຈະບັນທຶກສິ່ງທີ່ເກີດຂຶ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ແອັບສາມາດໃຊ້ບັນທຶກເຫຼົ່ານີ້ເພື່ອຊອກຫາ ແລະ ແກ້ໄຂບັນຫາໄດ້.\n\nບັນທຶກບາງຢ່າງອາດມີຂໍ້ມູນລະອຽດອ່ອນ, ດັ່ງນັ້ນໃຫ້ອະນຸຍາດສະເພາະແອັບທີ່ທ່ານເຊື່ອຖືໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດເທົ່ານັ້ນ. \n\nຫາກທ່ານບໍ່ອະນຸຍາດແອັບນີ້ໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດ, ມັນຈະຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກຂອງຕົວມັນເອງໄດ້ຢູ່. ຜູ້ຜະລິດອຸປະກອນຂອງທ່ານອາດຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກ ຫຼື ຂໍ້ມູນບາງຢ່າງຢູ່ອຸປະກອນຂອງທ່ານໄດ້."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"ບັນທຶກອຸປະກອນຈະບັນທຶກສິ່ງທີ່ເກີດຂຶ້ນຢູ່ອຸປະກອນຂອງທ່ານ. ແອັບສາມາດໃຊ້ບັນທຶກເຫຼົ່ານີ້ເພື່ອຊອກຫາ ແລະ ແກ້ໄຂບັນຫາໄດ້.\n\nບັນທຶກບາງຢ່າງອາດມີຂໍ້ມູນລະອຽດອ່ອນ, ດັ່ງນັ້ນໃຫ້ອະນຸຍາດສະເພາະແອັບທີ່ທ່ານເຊື່ອຖືໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດເທົ່ານັ້ນ. \n\nຫາກທ່ານບໍ່ອະນຸຍາດແອັບນີ້ໃຫ້ເຂົ້າເຖິງບັນທຶກອຸປະກອນທັງໝົດ, ມັນຈະຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກຂອງຕົວມັນເອງໄດ້ຢູ່. ຜູ້ຜະລິດອຸປະກອນຂອງທ່ານອາດຍັງຄົງສາມາດເຂົ້າເຖິງບັນທຶກ ຫຼື ຂໍ້ມູນບາງຢ່າງຢູ່ອຸປະກອນຂອງທ່ານໄດ້.\n\nສຶກສາເພີ່ມເຕີມໄດ້ຢູ່ g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ບໍ່ຕ້ອງສະແດງອີກ"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ຕ້ອງການສະແດງ <xliff:g id="APP_2">%2$s</xliff:g> ສະໄລ້"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ແກ້ໄຂ"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index a4ff5b8..667f502 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Дозволи еднократен пристап"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволувај"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Дневниците за евиденција на уредот снимаат што се случува на вашиот уред. Апликациите може да ги користат овие дневници за евиденција за да наоѓаат и поправаат проблеми.\n\nНекои дневници за евиденција може да содржат чувствителни податоци, па затоа дозволете им пристап до сите дневници за евиденција на уредот само на апликациите во кои имате доверба. \n\nАко не ѝ дозволите на апликацијава да пристапува до сите дневници за евиденција на уредот, таа сепак ќе може да пристапува до сопствените дневници за евиденција. Производителот на вашиот уред можеби сепак ќе може да пристапува до некои дневници за евиденција или податоци на уредот."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Дневниците за евиденција на уредот снимаат што се случува на вашиот уред. Апликациите може да ги користат овие дневници за евиденција за да наоѓаат и поправаат проблеми.\n\nНекои дневници за евиденција може да содржат чувствителни податоци, па затоа дозволете им пристап до сите дневници за евиденција на уредот само на апликациите во кои имате доверба. \n\nАко не ѝ дозволите на апликацијава да пристапува до сите дневници за евиденција на уредот, таа сепак ќе може да пристапува до сопствените дневници за евиденција. Производителот на вашиот уред можеби сепак ќе може да пристапува до некои дневници за евиденција или податоци на уредот.\n\nДознајте повеќе на g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Не прикажувај повторно"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> сака да прикажува делови од <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Измени"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 7f9d131..4bd2001 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ഒറ്റത്തവണ ആക്‌സസ് അനുവദിക്കുക"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"അനുവദിക്കരുത്"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ഉപകരണ ലോഗുകൾ നിങ്ങളുടെ ഉപകരണത്തിൽ എന്തൊക്കെയാണ് സംഭവിക്കുന്നതെന്ന് റെക്കോർഡ് ചെയ്യുന്നു. പ്രശ്‌നങ്ങൾ കണ്ടെത്തി പരിഹരിക്കുന്നതിന് ആപ്പുകൾക്ക് ഈ ലോഗുകൾ ഉപയോഗിക്കാൻ കഴിയും.\n\nചില ലോഗുകളിൽ സൂക്ഷ്‌മമായി കൈകാര്യം ചെയ്യേണ്ട വിവരങ്ങൾ അടങ്ങിയിരിക്കാൻ സാധ്യതയുള്ളതിനാൽ, എല്ലാ ഉപകരണ ലോഗുകളും ആക്സസ് ചെയ്യാനുള്ള അനുമതി നിങ്ങൾക്ക് വിശ്വാസമുള്ള ആപ്പുകൾക്ക് മാത്രം നൽകുക. \n\nഎല്ലാ ഉപകരണ ലോഗുകളും ആക്‌സസ് ചെയ്യാനുള്ള അനുവാദം നൽകിയില്ലെങ്കിലും, ഈ ആപ്പിന് അതിന്റെ സ്വന്തം ലോഗുകൾ ആക്‌സസ് ചെയ്യാനാകും. നിങ്ങളുടെ ഉപകരണ നിർമ്മാതാവിന് തുടർന്നും നിങ്ങളുടെ ഉപകരണത്തിലെ ചില ലോഗുകളോ വിവരങ്ങളോ ആക്‌സസ് ചെയ്യാനായേക്കും."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"ഉപകരണ ലോഗുകൾ നിങ്ങളുടെ ഉപകരണത്തിൽ എന്തൊക്കെയാണ് സംഭവിക്കുന്നതെന്ന് റെക്കോർഡ് ചെയ്യുന്നു. പ്രശ്‌നങ്ങൾ കണ്ടെത്തി പരിഹരിക്കുന്നതിന് ആപ്പുകൾക്ക് ഈ ലോഗുകൾ ഉപയോഗിക്കാൻ കഴിയും.\n\nചില ലോഗുകളിൽ സൂക്ഷ്‌മമായി കൈകാര്യം ചെയ്യേണ്ട വിവരങ്ങൾ അടങ്ങിയിരിക്കാൻ സാധ്യതയുള്ളതിനാൽ, എല്ലാ ഉപകരണ ലോഗുകളും ആക്സസ് ചെയ്യാനുള്ള അനുമതി നിങ്ങൾക്ക് വിശ്വാസമുള്ള ആപ്പുകൾക്ക് മാത്രം നൽകുക. \n\nഎല്ലാ ഉപകരണ ലോഗുകളും ആക്‌സസ് ചെയ്യാനുള്ള അനുവാദം നൽകിയില്ലെങ്കിലും, ഈ ആപ്പിന് അതിന്റെ സ്വന്തം ലോഗുകൾ ആക്‌സസ് ചെയ്യാനാകും. നിങ്ങളുടെ ഉപകരണ നിർമ്മാതാവിന് തുടർന്നും നിങ്ങളുടെ ഉപകരണത്തിലെ ചില ലോഗുകളോ വിവരങ്ങളോ ആക്‌സസ് ചെയ്യാനായേക്കും.\n\ng.co/android/devicelogs എന്നതിൽ കൂടുതലറിയുക."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"വീണ്ടും കാണിക്കരുത്"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> സ്ലൈസുകൾ കാണിക്കാൻ <xliff:g id="APP_0">%1$s</xliff:g> താൽപ്പര്യപ്പെടുന്നു"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"എഡിറ്റ് ചെയ്യുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index ecea6c0..1b92252 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Нэг удаагийн хандалтыг зөвшөөрнө үү"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Бүү зөвшөөр"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Төхөөрөмжийн лог нь таны төхөөрөмж дээр юу болж байгааг бичдэг. Аппууд эдгээр логийг асуудлыг олох болон засахад ашиглах боломжтой.\n\nЗарим лог эмзэг мэдээлэл агуулж байж магадгүй тул та зөвхөн итгэдэг аппууддаа төхөөрөмжийн бүх логт хандахыг зөвшөөрнө үү. \n\nХэрэв та энэ аппад төхөөрөмжийн бүх логт хандахыг зөвшөөрөхгүй бол энэ нь өөрийн логт хандах боломжтой хэвээр байх болно. Tаны төхөөрөмж үйлдвэрлэгч таны төхөөрөмж дээрх зарим лог эсвэл мэдээлэлд хандах боломжтой хэвээр байж магадгүй."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Төхөөрөмжийн лог нь таны төхөөрөмж дээр юу болж байгааг бичдэг. Аппууд эдгээр логийг асуудлыг олох болон засахад ашиглах боломжтой.\n\nЗарим лог эмзэг мэдээлэл агуулж байж магадгүй тул та зөвхөн итгэдэг аппууддаа төхөөрөмжийн бүх логт хандахыг зөвшөөрнө үү. \n\nХэрэв та энэ аппад төхөөрөмжийн бүх логт хандахыг зөвшөөрөхгүй бол энэ нь өөрийн логт хандах боломжтой хэвээр байх болно. Таны төхөөрөмжийн үйлдвэрлэгч таны төхөөрөмж дээрх зарим лог эсвэл мэдээлэлд хандах боломжтой хэвээр байж магадгүй.\n\ng.co/android/devicelogs -с нэмэлт мэдээлэл аваарай."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Дахиж бүү харуул"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> <xliff:g id="APP_2">%2$s</xliff:g>-н хэсгүүдийг (slices) харуулах хүсэлтэй байна"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Засах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 01989c4..fd7ce2e 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"एक वेळ अ‍ॅक्सेसची अनुमती द्या"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"अनुमती देऊ नका"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"तुमच्या डिव्हाइसवर काय होते ते डिव्हाइस लॉग रेकॉर्ड करते. समस्या शोधण्यासाठी आणि त्यांचे निराकरण करण्याकरिता ॲप्स हे लॉग वापरू शकतात.\n\nकाही लॉगमध्ये संवेदनशील माहिती असू शकते, त्यामुळे फक्त तुमचा विश्वास असलेल्या ॲप्सना सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती द्या. \n\nतुम्ही या ॲपला सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती न दिल्यास, ते तरीही त्याचा स्वतःचा लॉग अ‍ॅक्सेस करू शकते. तुमच्या डिव्हाइसचा उत्पादक तरीही काही लॉग किंवा तुमच्या डिव्हाइसवरील माहिती अ‍ॅक्सेस करू शकतो."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"तुमच्या डिव्हाइसवर काय होते ते डिव्हाइस लॉग रेकॉर्ड करते. समस्या शोधण्यासाठी आणि त्यांचे निराकरण करण्याकरिता ॲप्स हे लॉग वापरू शकतात.\n\nकाही लॉगमध्ये संवेदनशील माहिती असू शकते, त्यामुळे फक्त तुमचा विश्वास असलेल्या ॲप्सना सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती द्या. \n\nतुम्ही या ॲपला सर्व डिव्हाइस लॉग अ‍ॅक्सेस करण्याची अनुमती न दिल्यास, ते तरीही त्याचा स्वतःचा लॉग अ‍ॅक्सेस करू शकते. तुमच्या डिव्हाइसचा उत्पादक तरीही काही लॉग किंवा तुमच्या डिव्हाइसवरील माहिती अ‍ॅक्सेस करू शकतो.\n\ng.co/android/devicelogs येथे अधिक जाणून घ्या."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"पुन्हा दाखवू नका"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ला <xliff:g id="APP_2">%2$s</xliff:g> चे तुकडे दाखवायचे आहेत"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"संपादित करा"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 511546d..5a623be 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Benarkan akses satu kali"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Jangan benarkan"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Log peranti merekodkan perkara yang berlaku pada peranti anda. Apl dapat menggunakan log ini untuk menemukan dan membetulkan isu.\n\nSesetengah log mungkin mengandungi maklumat sensitif, jadi benarkan apl yang anda percaya sahaja untuk mengakses semua log peranti. \n\nJika anda tidak membenarkan apl ini mengakses semua log peranti, apl masih boleh mengakses log sendiri. Pengilang peranti anda mungkin masih dapat mengakses sesetengah log atau maklumat pada peranti anda."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Log peranti merekodkan perkara yang berlaku pada peranti anda. Apl boleh menggunakan log ini untuk menemukan dan membetulkan masalah.\n\nSesetengah log mungkin mengandungi maklumat sensitif, jadi hanya benarkan apl yang anda percaya untuk mengakses semua log peranti. \n\nJika anda tidak membenarkan apl ini mengakses semua log peranti, apl ini masih boleh mengakses log sendiri. Pengilang peranti anda mungkin masih dapat mengakses sesetengah log atau maklumat pada peranti anda.\n\nKetahui lebih lanjut di g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Jangan tunjuk lagi"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> mahu menunjukkan <xliff:g id="APP_2">%2$s</xliff:g> hirisan"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edit"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 90c88b6..abc5867 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Gi éngangstilgang"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Ikke tillat"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Enhetslogger registrerer det som skjer på enheten din. Apper kan bruke disse loggene til å finne og løse problemer.\n\nNoen logger kan inneholde sensitiv informasjon, så du bør bare gi tilgang til alle enhetslogger til apper du stoler på. \n\nHvis du ikke gir denne appen tilgang til alle enhetslogger, har den fortsatt tilgang til sine egne logger. Enhetsprodusenten kan fortsatt ha tilgang til visse logger eller noe informasjon på enheten din."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Enhetslogger registrerer det som skjer på enheten. Apper kan bruke disse loggene til å finne og løse problemer.\n\nNoen logger kan inneholde sensitiv informasjon, så du bør bare gi tilgang til alle enhetslogger til apper du stoler på. \n\nHvis du ikke gir denne appen tilgang til alle enhetslogger, har den fortsatt tilgang til sine egne logger. Enhetsprodusenten kan fortsatt ha tilgang til visse logger eller noe informasjon på enheten.\n\nFinn ut mer på g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Ikke vis igjen"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vil vise <xliff:g id="APP_2">%2$s</xliff:g>-utsnitt"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Endre"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 44aca780..251a53a 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Eenmalige toegang toestaan"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Niet toestaan"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Apparaatlogboeken leggen vast wat er op je apparaat gebeurt. Apps kunnen deze logboeken gebruiken om problemen op te sporen en te verhelpen.\n\nSommige logboeken kunnen gevoelige informatie bevatten, dus geef alleen apps die je vertrouwt toegang tot alle apparaatlogboeken. \n\nAls je deze app geen toegang tot alle apparaatlogboeken geeft, heeft de app nog wel toegang tot de eigen logboeken. De fabrikant van je apparaat heeft misschien nog steeds toegang tot bepaalde logboeken of informatie op je apparaat."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Apparaatlogboeken leggen vast wat er op je apparaat gebeurt. Apps kunnen deze logboeken gebruiken om problemen op te sporen en te verhelpen.\n\nSommige logboeken kunnen gevoelige informatie bevatten, dus geef alleen apps die je vertrouwt toegang tot alle apparaatlogboeken. \n\nAls je deze app geen toegang tot alle apparaatlogboeken geeft, heeft de app nog wel toegang tot de eigen logboeken. De fabrikant van je apparaat heeft misschien nog steeds toegang tot bepaalde logboeken of informatie op je apparaat.\n\nGa voor meer informatie naar g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Niet opnieuw tonen"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> wil segmenten van <xliff:g id="APP_2">%2$s</xliff:g> tonen"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Bewerken"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index bfe9f0a..26bfeb4 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ଗୋଟିଏ-ଥର ଆକ୍ସେସ ପାଇଁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ଆପଣଙ୍କ ଡିଭାଇସରେ ଯାହା ହୁଏ ତାହା ଡିଭାଇସ ଲଗଗୁଡ଼ିକ ରେକର୍ଡ କରେ। ସମସ୍ୟାଗୁଡ଼ିକୁ ଖୋଜି ସମାଧାନ କରିବାକୁ ଆପ୍ସ ଏହି ଲଗଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିପାରିବ।\n\nକିଛି ଲଗରେ ସମ୍ବେଦନଶୀଳ ସୂଚନା ଥାଇପାରେ, ତେଣୁ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଆପଣ ବିଶ୍ୱାସ କରୁଥିବା ଆପ୍ସକୁ ହିଁ ଅନୁମତି ଦିଅନ୍ତୁ। \n\nଯଦି ଆପଣ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ, ତେବେ ବି ଏହା ନିଜର ଡିଭାଇସ ଲଗଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିପାରିବ। ଆପଣଙ୍କ ଡିଭାଇସର ନିର୍ମାତା ଏବେ ବି ଆପଣଙ୍କର ଡିଭାଇସରେ କିଛି ଲଗ କିମ୍ବା ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ସକ୍ଷମ ହୋଇପାରନ୍ତି।"</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"ଆପଣଙ୍କ ଡିଭାଇସରେ ଯାହା ହୁଏ ତାହା ଡିଭାଇସ ଲଗଗୁଡ଼ିକ ରେକର୍ଡ କରେ। ସମସ୍ୟାଗୁଡ଼ିକୁ ଖୋଜି ସମାଧାନ କରିବାକୁ ଆପ୍ସ ଏହି ଲଗଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିପାରିବ।\n\nକିଛି ଲଗରେ ସମ୍ବେଦନଶୀଳ ସୂଚନା ଥାଇପାରେ, ତେଣୁ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଆପଣ ବିଶ୍ୱାସ କରୁଥିବା ଆପ୍ସକୁ ହିଁ ଅନୁମତି ଦିଅନ୍ତୁ। \n\nଯଦି ଆପଣ ସମସ୍ତ ଡିଭାଇସ ଲଗକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ଏହି ଆପକୁ ଅନୁମତି ଦିଅନ୍ତି ନାହିଁ, ତେବେ ବି ଏହା ନିଜର ଡିଭାଇସ ଲଗଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିପାରିବ। ଆପଣଙ୍କ ଡିଭାଇସର ନିର୍ମାତା ଏବେ ବି ଆପଣଙ୍କର ଡିଭାଇସରେ କିଛି ଲଗ କିମ୍ବା ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ ସକ୍ଷମ ହୋଇପାରନ୍ତି।\n\ng.co/android/devicelogsରେ ଅଧିକ ଜାଣନ୍ତୁ।"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ପୁଣି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g>, <xliff:g id="APP_2">%2$s</xliff:g> ସ୍ଲାଇସ୍‌କୁ ଦେଖାଇବା ପାଇଁ ଚାହେଁ"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ଏଡିଟ କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 7cd059a..b61b0fe 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ਇੱਕ-ਵਾਰ ਲਈ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ਆਗਿਆ ਨਾ ਦਿਓ"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"ਡੀਵਾਈਸ ਲੌਗਾਂ ਵਿੱਚ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ ਰਿਕਾਰਡ ਹੁੰਦੀਆਂ ਹਨ। ਐਪਾਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਲੱਭਣ ਅਤੇ ਉਨ੍ਹਾਂ ਦਾ ਹੱਲ ਕਰਨ ਲਈ ਇਨ੍ਹਾਂ ਲੌਗਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀਆਂ ਹਨ।\n\nਕੁਝ ਲੌਗਾਂ ਵਿੱਚ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ, ਇਸ ਲਈ ਸਿਰਫ਼ ਆਪਣੀਆਂ ਭਰੋਸੇਯੋਗ ਐਪਾਂ ਨੂੰ ਹੀ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ। \n\nਜੇ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਇਹ ਹਾਲੇ ਵੀ ਆਪਣੇ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ। ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਨਿਰਮਾਤਾ ਹਾਲੇ ਵੀ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਮੌਜੂਦ ਕੁਝ ਲੌਗਾਂ ਜਾਂ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦਾ ਹੈ।"</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"ਡੀਵਾਈਸ ਲੌਗਾਂ ਵਿੱਚ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ ਰਿਕਾਰਡ ਹੁੰਦੀਆਂ ਹਨ। ਐਪਾਂ ਸਮੱਸਿਆਵਾਂ ਨੂੰ ਲੱਭਣ ਅਤੇ ਉਨ੍ਹਾਂ ਦਾ ਹੱਲ ਕਰਨ ਲਈ ਇਨ੍ਹਾਂ ਲੌਗਾਂ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੀਆਂ ਹਨ।\n\nਕੁਝ ਲੌਗਾਂ ਵਿੱਚ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀ ਹੈ, ਇਸ ਲਈ ਸਿਰਫ਼ ਆਪਣੀਆਂ ਭਰੋਸੇਯੋਗ ਐਪਾਂ ਨੂੰ ਹੀ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ। \n\nਜੇ ਤੁਸੀਂ ਇਸ ਐਪ ਨੂੰ ਸਾਰੇ ਡੀਵਾਈਸ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਇਹ ਹਾਲੇ ਵੀ ਆਪਣੇ ਲੌਗਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ। ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਨਿਰਮਾਤਾ ਹਾਲੇ ਵੀ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਮੌਜੂਦ ਕੁਝ ਲੌਗਾਂ ਜਾਂ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦਾ ਹੈ।\n\ng.co/android/devicelogs \'ਤੇ ਹੋਰ ਜਾਣੋ।"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ਦੀ <xliff:g id="APP_2">%2$s</xliff:g> ਦੇ ਹਿੱਸੇ ਦਿਖਾਉਣ ਦੀ ਇੱਛਾ ਹੈ"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"ਸੰਪਾਦਨ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 974b6f6..7193eb7 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -2053,8 +2053,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Zezwól na jednorazowy dostęp"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nie zezwalaj"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Dzienniki urządzenia zapisują, co dzieje się na urządzeniu. Aplikacje mogą ich używać do wykrywania i rozwiązywania problemów.\n\nNiektóre dzienniki mogą zawierać poufne dane, dlatego na dostęp do wszystkich dzienników zezwalaj tylko aplikacjom, którym ufasz. \n\nNawet jeśli nie zezwolisz tej aplikacji na dostęp do wszystkich dzienników na urządzeniu, będzie mogła korzystać z własnych. Producent urządzenia nadal będzie mógł używać niektórych dzienników na urządzeniu."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Dzienniki urządzenia zapisują, co dzieje się na urządzeniu. Aplikacje mogą ich używać do wykrywania i rozwiązywania problemów.\n\nNiektóre dzienniki mogą zawierać poufne dane, dlatego na dostęp do wszystkich dzienników zezwalaj tylko aplikacjom, którym ufasz. \n\nNawet jeśli nie zezwolisz tej aplikacji na dostęp do wszystkich dzienników na urządzeniu, będzie mogła korzystać z własnych. Producent urządzenia nadal będzie mógł używać niektórych dzienników na urządzeniu.\n\nWięcej informacji znajdziesz na stronie g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nie pokazuj ponownie"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Aplikacja <xliff:g id="APP_0">%1$s</xliff:g> chce pokazywać wycinki z aplikacji <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Edytuj"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 0c3a8f9..c1c0d54 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -2052,8 +2052,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir o acesso único"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Os registros do dispositivo gravam o que acontece nele. Os apps podem usar esses registros para encontrar e corrigir problemas.\n\nAlguns registros podem conter informações sensíveis, então autorize o acesso a eles apenas para os apps em que você confia. \n\nSe você não permitir que esse app acesse todos os registros do dispositivo, ele ainda vai poder acessar os próprios. O fabricante do dispositivo também pode ter acesso a alguns registros ou informações."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Os registros do dispositivo gravam o que acontece nele. Os apps podem usar esses registros para encontrar e corrigir problemas.\n\nAlguns registros podem conter informações sensíveis, então autorize o acesso a eles apenas para os apps em que você confia. \n\nSe você não permitir que esse app acesse todos os registros do dispositivo, ele ainda vai poder acessar os próprios. O fabricante do dispositivo também pode ter acesso a alguns registros ou informações.\n\nSaiba mais em g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar novamente"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes do app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index a99f49a..1fe6e1c 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -186,7 +186,7 @@
     <string name="ssl_ca_cert_noti_by_administrator" msgid="4564941950768783879">"Pelo gestor do seu perfil de trabalho"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="217337232273211674">"Por <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
     <string name="work_profile_deleted" msgid="5891181538182009328">"Perfil de trabalho eliminado"</string>
-    <string name="work_profile_deleted_details" msgid="3773706828364418016">"A app de administração do perfil de trabalho está em falta ou danificada. Consequentemente, o seu perfil de trabalho e os dados relacionados foram eliminados. Contacte o gestor para obter assistência."</string>
+    <string name="work_profile_deleted_details" msgid="3773706828364418016">"A app de administração do perfil de trabalho está em falta ou danificada. Por isso, o seu perfil de trabalho e os dados relacionados foram eliminados. Contacte o gestor para obter assistência."</string>
     <string name="work_profile_deleted_description_dpm_wipe" msgid="2477244968924647232">"O seu perfil de trabalho já não está disponível neste dispositivo"</string>
     <string name="work_profile_deleted_reason_maximum_password_failure" msgid="1080323158315663167">"Demasiadas tentativas de introdução da palavra-passe"</string>
     <string name="device_ownership_relinquished" msgid="4080886992183195724">"O administrador anulou o dispositivo para utilização pessoal."</string>
@@ -2052,8 +2052,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir acesso único"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Os registos do dispositivo documentam o que ocorre no seu dispositivo. As apps podem usar esses registos para detetar e corrigir problemas.\n\nAlguns registos podem conter informações confidenciais e, por isso, o acesso a todos os registos do dispositivo deve apenas ser permitido às apps nas quais confia. \n\nSe não permitir o acesso desta app a todos os registos do dispositivo, esta pode ainda assim aceder aos próprios registos. O fabricante do dispositivo pode continuar a aceder a alguns registos ou informações no seu dispositivo."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Os registos do dispositivo documentam o que ocorre no seu dispositivo. As apps podem usar esses registos para detetar e corrigir problemas.\n\nAlguns registos podem conter informações confidenciais e, por isso, o acesso a todos os registos do dispositivo só deve ser permitido às apps nas quais confia. \n\nSe não permitir o acesso desta app a todos os registos do dispositivo, esta pode ainda assim aceder aos próprios registos. O fabricante do dispositivo pode continuar a aceder a alguns registos ou informações no seu dispositivo.\n\nSaiba mais em g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar de novo"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"A app <xliff:g id="APP_0">%1$s</xliff:g> pretende mostrar partes da app <xliff:g id="APP_2">%2$s</xliff:g>."</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 0c3a8f9..c1c0d54 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -2052,8 +2052,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permitir o acesso único"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Não permitir"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Os registros do dispositivo gravam o que acontece nele. Os apps podem usar esses registros para encontrar e corrigir problemas.\n\nAlguns registros podem conter informações sensíveis, então autorize o acesso a eles apenas para os apps em que você confia. \n\nSe você não permitir que esse app acesse todos os registros do dispositivo, ele ainda vai poder acessar os próprios. O fabricante do dispositivo também pode ter acesso a alguns registros ou informações."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Os registros do dispositivo gravam o que acontece nele. Os apps podem usar esses registros para encontrar e corrigir problemas.\n\nAlguns registros podem conter informações sensíveis, então autorize o acesso a eles apenas para os apps em que você confia. \n\nSe você não permitir que esse app acesse todos os registros do dispositivo, ele ainda vai poder acessar os próprios. O fabricante do dispositivo também pode ter acesso a alguns registros ou informações.\n\nSaiba mais em g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Não mostrar novamente"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> quer mostrar partes do app <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editar"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 24615ee..129f8fe 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -2052,8 +2052,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Permite accesul o dată"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nu permite"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Jurnalele dispozitivului înregistrează activitatea de pe dispozitivul tău. Aplicațiile pot folosi aceste jurnale pentru a identifica și a remedia probleme.\n\nUnele jurnale pot să conțină informații sensibile, prin urmare permite accesul la toate jurnalele dispozitivului doar aplicațiilor în care ai încredere. \n\nDacă nu permiți accesul aplicației la toate jurnalele dispozitivului, aceasta poate în continuare să acceseze propriile jurnale. Este posibil ca producătorul dispozitivului să acceseze în continuare unele jurnale sau informații de pe dispozitiv."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Jurnalele dispozitivului înregistrează activitatea de pe acesta. Aplicațiile pot folosi aceste jurnale pentru a identifica și a remedia probleme.\n\nUnele jurnale pot să conțină informații sensibile, prin urmare permite accesul la toate jurnalele dispozitivului doar aplicațiilor în care ai încredere. \n\nDacă nu permiți accesul aplicației la toate jurnalele dispozitivului, aceasta poate în continuare să acceseze propriile jurnale. E posibil ca producătorul dispozitivului să acceseze în continuare unele jurnale sau informații de pe dispozitiv.\n\nAflă mai multe la g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Nu mai afișa"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> vrea să afișeze porțiuni din <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Editează"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index e28df10..5a9e0c1 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -2053,8 +2053,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Povoliť jednorazový prístup"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Nepovoliť"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Denníky zariadenia zaznamenávajú, čo sa deje vo vašom zariadení. Aplikácie môžu pomocou týchto denníkov vyhľadávať a riešiť problémy.\n\nNiektoré denníky môžu obsahovať citlivé údaje, preto povoľte prístup k všetkým denníkom zariadenia iba dôveryhodným aplikáciám. \n\nAk tejto aplikácii nepovolíte prístup k všetkým denníkom zariadenia, stále bude mať prístup k vlastným denníkom. Výrobca vášho zariadenia bude mať naďalej prístup k niektorým denníkom alebo informáciám vo vašom zariadení."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Denníky zariadenia zaznamenávajú, čo sa deje vo vašom zariadení. Aplikácie môžu pomocou týchto denníkov vyhľadávať a riešiť problémy.\n\nNiektoré denníky môžu obsahovať citlivé údaje, preto povoľte prístup k všetkým denníkom zariadenia iba dôveryhodným aplikáciám. \n\nAk tejto aplikácii nepovolíte prístup k všetkým denníkom zariadenia, stále bude mať prístup k vlastným denníkom. Výrobca vášho zariadenia bude mať naďalej prístup k niektorým denníkom alebo informáciám vo vašom zariadení.\n\nViac sa dozviete na g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Už nezobrazovať"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> chce zobrazovať rezy z aplikácie <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Upraviť"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 57a9a5b..4747297 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -2052,8 +2052,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Дозволи једнократан приступ"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Не дозволи"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Евиденције уређаја региструју шта се дешава на уређају. Апликације могу да користе те евиденције да би пронашле и решиле проблеме.\n\nНеке евиденције могу да садрже осетљиве информације, па приступ свим евиденцијама уређаја треба да дозвољавате само апликацијама у које имате поверења. \n\nАко не дозволите овој апликацији да приступа свим евиденцијама уређаја, она и даље може да приступа сопственим евиденцијама. Произвођач уређаја ће можда и даље моћи да приступа неким евиденцијама или информацијама на уређају."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Евиденције уређаја региструју шта се дешава на уређају. Апликације могу да користе те евиденције да би пронашле и решиле проблеме.\n\nНеке евиденције могу да садрже осетљиве информације, па приступ свим евиденцијама уређаја треба да дозвољавате само апликацијама у које имате поверења. \n\nАко не дозволите овој апликацији да приступа свим евиденцијама уређаја, она и даље може да приступа сопственим евиденцијама. Произвођач уређаја ће можда и даље моћи да приступа неким евиденцијама или информацијама на уређају.\n\nСазнајте више на g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Не приказуј поново"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Апликација <xliff:g id="APP_0">%1$s</xliff:g> жели да приказује исечке из апликације <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"Измени"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index f4f2da0..fae3b07 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -2291,7 +2291,7 @@
     <string name="notification_content_abusive_bg_apps" msgid="5296898075922695259">"<xliff:g id="APP">%1$s</xliff:g> inatumika chinichini. Gusa ili udhibiti matumizi ya betri."</string>
     <string name="notification_content_long_running_fgs" msgid="8258193410039977101">"<xliff:g id="APP">%1$s</xliff:g> inaweza kuathiri muda wa matumizi ya betri. Gusa ili ukague programu zinazotumika."</string>
     <string name="notification_action_check_bg_apps" msgid="4758877443365362532">"Angalia programu zinazotumika"</string>
-    <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Haiwezi kufikia kamera ya simu kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string>
+    <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Huwezi kufikia kamera ya simu kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Haiwezi kufikia kamera ya kompyuta kibao kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Huwezi kufikia maudhui haya unapotiririsha. Badala yake jaribu kwenye simu yako."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Chaguomsingi la mfumo"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index e2502ba..b08b86b 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"ஒருமுறை அணுகலை அனுமதி"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"அனுமதிக்க வேண்டாம்"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"உங்கள் சாதனத்தில் நடப்பவற்றைச் சாதனப் பதிவுகள் ரெக்கார்டு செய்யும். சிக்கல்களைக் கண்டறிந்து சரிசெய்ய ஆப்ஸ் இந்தப் பதிவுகளைப் பயன்படுத்தலாம்.\n\nபாதுகாக்கப்பட வேண்டிய தகவல்கள் சில பதிவுகளில் இருக்கக்கூடும் என்பதால் சாதனப் பதிவுகள் அனைத்தையும் அணுக நீங்கள் நம்பும் ஆப்ஸை மட்டும் அனுமதிக்கவும். \n\nசாதனப் பதிவுகள் அனைத்தையும் அணுக இந்த ஆப்ஸை அனுமதிக்கவில்லை என்றாலும் அதற்குச் சொந்தமான பதிவுகளை அதனால் அணுக முடியும். உங்கள் சாதனத்திலுள்ள சில பதிவுகளையோ தகவல்களையோ சாதன உற்பத்தியாளரால் தொடர்ந்து அணுக முடியும்."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"உங்கள் சாதனத்தில் நடப்பவற்றைச் சாதனப் பதிவுகள் ரெக்கார்டு செய்யும். சிக்கல்களைக் கண்டறிந்து சரிசெய்ய ஆப்ஸால் இந்தப் பதிவுகளைப் பயன்படுத்த முடியும்.\n\nபாதுகாக்கப்பட வேண்டிய தகவல்கள், சில பதிவுகளில் இருக்கக்கூடும் என்பதால் சாதனப் பதிவுகள் அனைத்தையும் அணுக உங்களுக்கு நம்பகமான ஆப்ஸை மட்டும் அனுமதிக்கவும். \n\nசாதனப் பதிவுகள் அனைத்தையும் அணுக இந்த ஆப்ஸை நீங்கள் அனுமதிக்கவில்லை என்றாலும் அதற்குச் சொந்தமான பதிவுகளை அதனால் அணுக முடியும். உங்கள் சாதனத்திலுள்ள சில பதிவுகளையோ தகவல்களையோ சாதன உற்பத்தியாளரால் தொடர்ந்து அணுக முடியும்.\n\n மேலும் அறிந்துகொள்ள g.co/android/devicelogs இணைப்பிற்குச் செல்லுங்கள்."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"மீண்டும் காட்டாதே"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_2">%2$s</xliff:g> ஆப்ஸின் விழிப்பூட்டல்களைக் காண்பிக்க, <xliff:g id="APP_0">%1$s</xliff:g> அனுமதி கேட்கிறது"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"திருத்து"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 5d98379..6af5165 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"อนุญาตสิทธิ์เข้าถึงแบบครั้งเดียว"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"ไม่อนุญาต"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"บันทึกของอุปกรณ์เก็บข้อมูลสิ่งที่เกิดขึ้นในอุปกรณ์ แอปสามารถใช้บันทึกเหล่านี้เพื่อค้นหาและแก้ไขปัญหา\n\nบันทึกบางรายการอาจมีข้อมูลที่ละเอียดอ่อน คุณจึงควรอนุญาตเฉพาะแอปที่เชื่อถือได้ให้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ \n\nหากคุณไม่อนุญาตให้แอปนี้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ แอปจะยังเข้าถึงบันทึกของตัวเองได้อยู่ ผู้ผลิตอุปกรณ์อาจยังเข้าถึงบันทึกหรือข้อมูลบางรายการในอุปกรณ์ของคุณได้"</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"บันทึกของอุปกรณ์เก็บข้อมูลสิ่งที่เกิดขึ้นในอุปกรณ์ แอปสามารถใช้บันทึกเหล่านี้เพื่อค้นหาและแก้ไขปัญหา\n\nบันทึกบางรายการอาจมีข้อมูลที่ละเอียดอ่อน คุณจึงควรอนุญาตเฉพาะแอปที่เชื่อถือได้ให้เข้าถึงบันทึกทั้งหมดของอุปกรณ์\n\nหากคุณไม่อนุญาตให้แอปนี้เข้าถึงบันทึกทั้งหมดของอุปกรณ์ แอปจะยังเข้าถึงบันทึกของตัวเองได้อยู่ ผู้ผลิตอุปกรณ์อาจยังเข้าถึงบันทึกหรือข้อมูลบางรายการในอุปกรณ์ได้\n\nดูข้อมูลเพิ่มเติมที่ g.co/android/devicelogs"</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"ไม่ต้องแสดงอีก"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"<xliff:g id="APP_0">%1$s</xliff:g> ต้องการแสดงส่วนต่างๆ ของ <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"แก้ไข"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 5e32214..7bb0ba9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -2051,8 +2051,7 @@
     <string name="log_access_confirmation_allow" msgid="5302517782599389507">"Payagan ang isang beses na pag-access"</string>
     <string name="log_access_confirmation_deny" msgid="7685790957455099845">"Huwag payagan"</string>
     <string name="log_access_confirmation_body" product="default" msgid="1806692062668620735">"Nire-record ng mga log ng device kung ano ang nangyayari sa iyong device. Magagamit ng mga app ang mga log na ito para maghanap at mag-ayos ng mga isyu.\n\nPosibleng maglaman ang ilang log ng sensitibong impormasyon, kaya ang mga app lang na pinagkakatiwalaan mo ang payagang maka-access sa lahat ng log ng device. \n\nKung hindi mo papayagan ang app na ito na i-access ang lahat ng log ng device, maa-access pa rin nito ang mga sarili nitong log. Posible pa ring ma-access ng manufacturer ng iyong device ang ilang log o impormasyon sa device mo."</string>
-    <!-- no translation found for log_access_confirmation_body (7379536536425265262) -->
-    <skip />
+    <string name="log_access_confirmation_body" product="tv" msgid="7379536536425265262">"Nire-record ng mga log ng device kung ano ang nangyayari sa iyong device. Magagamit ng mga app ang mga log na ito para maghanap at mag-ayos ng mga isyu.\n\nPosibleng maglaman ang ilang log ng sensitibong impormasyon, kaya ang mga app lang na pinagkakatiwalaan mo ang payagang maka-access sa lahat ng log ng device. \n\nKung hindi mo papayagan ang app na ito na i-access ang lahat ng log ng device, maa-access pa rin nito ang mga sarili nitong log. Posible pa ring ma-access ng manufacturer ng iyong device ang ilang log o impormasyon sa device mo.\n\nMatuto pa sa g.co/android/devicelogs."</string>
     <string name="log_access_do_not_show_again" msgid="1058690599083091552">"Huwag ipakita ulit"</string>
     <string name="slices_permission_request" msgid="3677129866636153406">"Gustong ipakita ng <xliff:g id="APP_0">%1$s</xliff:g> ang mga slice ng <xliff:g id="APP_2">%2$s</xliff:g>"</string>
     <string name="screenshot_edit" msgid="7408934887203689207">"I-edit"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index a45b1a4..f78c64e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1233,7 +1233,7 @@
     <string name="unsupported_display_size_show" msgid="980129850974919375">"Luôn hiển thị"</string>
     <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> được xây dựng cho phiên bản không tương thích của hệ điều hành Android và có thể hoạt động không như mong đợi. Bạn có thể sử dụng phiên bản cập nhật của ứng dụng."</string>
     <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Luôn hiển thị"</string>
-    <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Kiểm tra bản cập nhật"</string>
+    <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Kiểm tra để tìm bản cập nhật"</string>
     <string name="smv_application" msgid="3775183542777792638">"Ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> (quá trình <xliff:g id="PROCESS">%2$s</xliff:g>) đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
     <string name="smv_process" msgid="1398801497130695446">"Quá trình <xliff:g id="PROCESS">%1$s</xliff:g> đã vi phạm chính sách StrictMode tự thi hành của mình."</string>
     <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Điện thoại đang cập nhật…"</string>
@@ -1959,7 +1959,7 @@
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên máy tính bảng."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Hiện tại, bạn không thể truy cập vào ứng dụng này trên <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy thử trên điện thoại."</string>
     <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Ứng dụng này được xây dựng cho một phiên bản Android cũ hơn và có thể hoạt động không bình thường. Hãy thử kiểm tra các bản cập nhật hoặc liên hệ với nhà phát triển."</string>
-    <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kiểm tra bản cập nhật"</string>
+    <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Kiểm tra để tìm bản cập nhật"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Bạn có tin nhắn mới"</string>
     <string name="new_sms_notification_content" msgid="3197949934153460639">"Mở ứng dụng SMS để xem"</string>
     <string name="profile_encrypted_title" msgid="9001208667521266472">"Một số chức năng có thể bị hạn chế"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index dae4c35..c67f9fa 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -651,9 +651,9 @@
     <string name="face_acquired_recalibrate" msgid="8724013080976469746">"請重新註冊面孔。"</string>
     <string name="face_acquired_too_different" msgid="2520389515612972889">"無法辨識面孔,請再試一次。"</string>
     <string name="face_acquired_too_similar" msgid="8882920552674125694">"請稍為轉換頭部的位置"</string>
-    <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"盡可能直視手機"</string>
+    <string name="face_acquired_pan_too_extreme" msgid="5417928604710621088">"請正面望向手機"</string>
     <string name="face_acquired_tilt_too_extreme" msgid="5715715666540716620">"請正面望向手機"</string>
-    <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"盡可能直視手機"</string>
+    <string name="face_acquired_roll_too_extreme" msgid="8261939882838881194">"請正面望向手機"</string>
     <string name="face_acquired_obscured" msgid="4917643294953326639">"移開遮住面孔的任何物件。"</string>
     <string name="face_acquired_sensor_dirty" msgid="8968391891086721678">"請清理螢幕頂部,包括黑色列"</string>
     <!-- no translation found for face_acquired_dark_glasses_detected (5643703296620631986) -->
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index f790787..0aae6a5 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -23,13 +23,13 @@
     <string name="pip_phone_enter_split" msgid="7042877263880641911">"Accesează ecranul împărțit"</string>
     <string name="pip_menu_title" msgid="5393619322111827096">"Meniu"</string>
     <string name="pip_notification_title" msgid="1347104727641353453">"<xliff:g id="NAME">%s</xliff:g> este în modul picture-in-picture"</string>
-    <string name="pip_notification_message" msgid="8854051911700302620">"Dacă nu doriți ca <xliff:g id="NAME">%s</xliff:g> să utilizeze această funcție, atingeți pentru a deschide setările și dezactivați-o."</string>
+    <string name="pip_notification_message" msgid="8854051911700302620">"Dacă nu vrei ca <xliff:g id="NAME">%s</xliff:g> să folosească această funcție, atinge pentru a deschide setările și dezactiveaz-o."</string>
     <string name="pip_play" msgid="3496151081459417097">"Redă"</string>
     <string name="pip_pause" msgid="690688849510295232">"Întrerupe"</string>
-    <string name="pip_skip_to_next" msgid="8403429188794867653">"Treceți la următorul"</string>
-    <string name="pip_skip_to_prev" msgid="7172158111196394092">"Treceți la cel anterior"</string>
-    <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionați"</string>
-    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stocați"</string>
+    <string name="pip_skip_to_next" msgid="8403429188794867653">"Treci la următorul"</string>
+    <string name="pip_skip_to_prev" msgid="7172158111196394092">"Treci la cel anterior"</string>
+    <string name="accessibility_action_pip_resize" msgid="4623966104749543182">"Redimensionează"</string>
+    <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"Stochează"</string>
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Anulează stocarea"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Este posibil ca aplicația să nu funcționeze cu ecranul împărțit."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplicația nu acceptă ecranul împărțit."</string>
@@ -47,9 +47,9 @@
     <string name="accessibility_action_divider_top_30" msgid="3572788224908570257">"Partea de sus: 30%"</string>
     <string name="accessibility_action_divider_bottom_full" msgid="2831868345092314060">"Partea de jos pe ecran complet"</string>
     <string name="one_handed_tutorial_title" msgid="4583241688067426350">"Folosirea modului cu o mână"</string>
-    <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pentru a ieși, glisați în sus din partea de jos a ecranului sau atingeți oriunde deasupra ferestrei aplicației"</string>
+    <string name="one_handed_tutorial_description" msgid="3486582858591353067">"Pentru a ieși, glisează în sus din partea de jos a ecranului sau atinge oriunde deasupra ferestrei aplicației"</string>
     <string name="accessibility_action_start_one_handed" msgid="5070337354072861426">"Activează modul cu o mână"</string>
-    <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Părăsiți modul cu o mână"</string>
+    <string name="accessibility_action_stop_one_handed" msgid="1369940261782179442">"Ieși din modul cu o mână"</string>
     <string name="bubbles_settings_button_description" msgid="1301286017420516912">"Setări pentru baloanele <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="bubble_overflow_button_content_description" msgid="8160974472718594382">"Suplimentar"</string>
     <string name="bubble_accessibility_action_add_back" msgid="1830101076853540953">"Adaugă înapoi în stivă"</string>
@@ -61,27 +61,27 @@
     <string name="bubble_accessibility_action_move_bottom_right" msgid="2107626346109206352">"Mută în dreapta jos"</string>
     <string name="bubbles_app_settings" msgid="3617224938701566416">"Setări <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
     <string name="bubble_dismiss_text" msgid="8816558050659478158">"Închide balonul"</string>
-    <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nu afișați conversația în balon"</string>
+    <string name="bubbles_dont_bubble_conversation" msgid="310000317885712693">"Nu afișa conversația în balon"</string>
     <string name="bubbles_user_education_title" msgid="2112319053732691899">"Chat cu baloane"</string>
-    <string name="bubbles_user_education_description" msgid="4215862563054175407">"Conversațiile noi apar ca pictograme flotante sau baloane. Atingeți pentru a deschide balonul. Trageți pentru a-l muta."</string>
-    <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controlați oricând baloanele"</string>
-    <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Atingeți Gestionați pentru a dezactiva baloanele din această aplicație"</string>
+    <string name="bubbles_user_education_description" msgid="4215862563054175407">"Conversațiile noi apar ca pictograme flotante sau baloane. Atinge pentru a deschide balonul. Trage pentru a-l muta."</string>
+    <string name="bubbles_user_education_manage_title" msgid="7042699946735628035">"Controlează oricând baloanele"</string>
+    <string name="bubbles_user_education_manage" msgid="3460756219946517198">"Atinge Gestionează pentru a dezactiva baloanele din această aplicație"</string>
     <string name="bubbles_user_education_got_it" msgid="3382046149225428296">"OK"</string>
     <string name="bubble_overflow_empty_title" msgid="2397251267073294968">"Nu există baloane recente"</string>
     <string name="bubble_overflow_empty_subtitle" msgid="2627417924958633713">"Baloanele recente și baloanele respinse vor apărea aici"</string>
     <string name="notification_bubble_title" msgid="6082910224488253378">"Balon"</string>
     <string name="manage_bubbles_text" msgid="7730624269650594419">"Gestionează"</string>
     <string name="accessibility_bubble_dismissed" msgid="8367471990421247357">"Balonul a fost respins."</string>
-    <string name="restart_button_description" msgid="6712141648865547958">"Atingeți ca să reporniți aplicația pentru o vizualizare mai bună."</string>
-    <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Aveți probleme cu camera foto?\nAtingeți pentru a reîncadra"</string>
-    <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nu ați remediat problema?\nAtingeți pentru a reveni"</string>
-    <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nu aveți probleme cu camera foto? Atingeți pentru a închide."</string>
+    <string name="restart_button_description" msgid="6712141648865547958">"Atinge ca să repornești aplicația pentru o vizualizare mai bună."</string>
+    <string name="camera_compat_treatment_suggested_button_description" msgid="8103916969024076767">"Ai probleme cu camera foto?\nAtinge pentru a reîncadra"</string>
+    <string name="camera_compat_treatment_applied_button_description" msgid="2944157113330703897">"Nu ai remediat problema?\nAtinge pentru a reveni"</string>
+    <string name="camera_compat_dismiss_button_description" msgid="2795364433503817511">"Nu ai probleme cu camera foto? Atinge pentru a închide."</string>
     <string name="letterbox_education_dialog_title" msgid="7739895354143295358">"Vezi și fă mai multe"</string>
     <string name="letterbox_education_split_screen_text" msgid="6206339484068670830">"Trage în altă aplicație pentru a folosi ecranul împărțit"</string>
     <string name="letterbox_education_reposition_text" msgid="4589957299813220661">"Atinge de două ori lângă o aplicație pentru a o repoziționa"</string>
     <string name="letterbox_education_got_it" msgid="4057634570866051177">"OK"</string>
     <string name="letterbox_education_expand_button_description" msgid="1729796567101129834">"Extinde pentru mai multe informații"</string>
-    <string name="maximize_button_text" msgid="1650859196290301963">"Maximizați"</string>
+    <string name="maximize_button_text" msgid="1650859196290301963">"Maximizează"</string>
     <string name="minimize_button_text" msgid="271592547935841753">"Minimizează"</string>
     <string name="close_button_text" msgid="2913281996024033299">"Închide"</string>
 </resources>
diff --git a/libs/WindowManager/Shell/res/values/config.xml b/libs/WindowManager/Shell/res/values/config.xml
index f03b7f6..30c3d50 100644
--- a/libs/WindowManager/Shell/res/values/config.xml
+++ b/libs/WindowManager/Shell/res/values/config.xml
@@ -19,6 +19,10 @@
          by the resources of the app using the Shell library. -->
     <bool name="config_enableShellMainThread">false</bool>
 
+    <!-- Determines whether to register the shell task organizer on init.
+         TODO(b/238217847): This config is temporary until we refactor the base WMComponent. -->
+    <bool name="config_registerShellTaskOrganizerOnInit">true</bool>
+
     <!-- Animation duration for PIP when entering. -->
     <integer name="config_pipEnterAnimationDuration">425</integer>
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
index 1c0e6f7..756d802 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationRunner.java
@@ -20,6 +20,9 @@
 import static android.view.WindowManagerPolicyConstants.TYPE_LAYER_OFFSET;
 import static android.window.TransitionInfo.FLAG_IS_BEHIND_STARTING_WINDOW;
 
+import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
+
 import android.animation.Animator;
 import android.animation.ValueAnimator;
 import android.content.Context;
@@ -42,7 +45,6 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
-import java.util.function.BiFunction;
 
 /** To run the ActivityEmbedding animations. */
 class ActivityEmbeddingAnimationRunner {
@@ -85,7 +87,7 @@
             @NonNull SurfaceControl.Transaction finishTransaction,
             @NonNull Runnable animationFinishCallback) {
         final List<ActivityEmbeddingAnimationAdapter> adapters =
-                createAnimationAdapters(info, startTransaction);
+                createAnimationAdapters(info, startTransaction, finishTransaction);
         long duration = 0;
         for (ActivityEmbeddingAnimationAdapter adapter : adapters) {
             duration = Math.max(duration, adapter.getDurationHint());
@@ -129,7 +131,8 @@
      */
     @NonNull
     private List<ActivityEmbeddingAnimationAdapter> createAnimationAdapters(
-            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction) {
+            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction) {
         boolean isChangeTransition = false;
         for (TransitionInfo.Change change : info.getChanges()) {
             if (change.hasFlags(FLAG_IS_BEHIND_STARTING_WINDOW)) {
@@ -145,23 +148,25 @@
             return createChangeAnimationAdapters(info, startTransaction);
         }
         if (Transitions.isClosingType(info.getType())) {
-            return createCloseAnimationAdapters(info);
+            return createCloseAnimationAdapters(info, startTransaction, finishTransaction);
         }
-        return createOpenAnimationAdapters(info);
+        return createOpenAnimationAdapters(info, startTransaction, finishTransaction);
     }
 
     @NonNull
     private List<ActivityEmbeddingAnimationAdapter> createOpenAnimationAdapters(
-            @NonNull TransitionInfo info) {
-        return createOpenCloseAnimationAdapters(info, true /* isOpening */,
-                mAnimationSpec::loadOpenAnimation);
+            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction) {
+        return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction,
+                true /* isOpening */, mAnimationSpec::loadOpenAnimation);
     }
 
     @NonNull
     private List<ActivityEmbeddingAnimationAdapter> createCloseAnimationAdapters(
-            @NonNull TransitionInfo info) {
-        return createOpenCloseAnimationAdapters(info, false /* isOpening */,
-                mAnimationSpec::loadCloseAnimation);
+            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction) {
+        return createOpenCloseAnimationAdapters(info, startTransaction, finishTransaction,
+                false /* isOpening */, mAnimationSpec::loadCloseAnimation);
     }
 
     /**
@@ -170,8 +175,9 @@
      */
     @NonNull
     private List<ActivityEmbeddingAnimationAdapter> createOpenCloseAnimationAdapters(
-            @NonNull TransitionInfo info, boolean isOpening,
-            @NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider) {
+            @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction, boolean isOpening,
+            @NonNull AnimationProvider animationProvider) {
         // We need to know if the change window is only a partial of the whole animation screen.
         // If so, we will need to adjust it to make the whole animation screen looks like one.
         final List<TransitionInfo.Change> openingChanges = new ArrayList<>();
@@ -194,7 +200,8 @@
         final List<ActivityEmbeddingAnimationAdapter> adapters = new ArrayList<>();
         for (TransitionInfo.Change change : openingChanges) {
             final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
-                    change, animationProvider, openingWholeScreenBounds);
+                    info, change, startTransaction, finishTransaction, animationProvider,
+                    openingWholeScreenBounds);
             if (isOpening) {
                 adapter.overrideLayer(offsetLayer++);
             }
@@ -202,7 +209,8 @@
         }
         for (TransitionInfo.Change change : closingChanges) {
             final ActivityEmbeddingAnimationAdapter adapter = createOpenCloseAnimationAdapter(
-                    change, animationProvider, closingWholeScreenBounds);
+                    info, change, startTransaction, finishTransaction, animationProvider,
+                    closingWholeScreenBounds);
             if (!isOpening) {
                 adapter.overrideLayer(offsetLayer++);
             }
@@ -213,10 +221,18 @@
 
     @NonNull
     private ActivityEmbeddingAnimationAdapter createOpenCloseAnimationAdapter(
-            @NonNull TransitionInfo.Change change,
-            @NonNull BiFunction<TransitionInfo.Change, Rect, Animation> animationProvider,
-            @NonNull Rect wholeAnimationBounds) {
-        final Animation animation = animationProvider.apply(change, wholeAnimationBounds);
+            @NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
+            @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction,
+            @NonNull AnimationProvider animationProvider, @NonNull Rect wholeAnimationBounds) {
+        final Animation animation = animationProvider.get(info, change, wholeAnimationBounds);
+        // We may want to show a background color for open/close transition.
+        final int backgroundColor = getTransitionBackgroundColorIfSet(info, change, animation,
+                0 /* defaultColor */);
+        if (backgroundColor != 0) {
+            addBackgroundToTransition(info.getRootLeash(), backgroundColor, startTransaction,
+                    finishTransaction);
+        }
         return new ActivityEmbeddingAnimationAdapter(animation, change, change.getLeash(),
                 wholeAnimationBounds);
     }
@@ -322,4 +338,10 @@
         return ScreenshotUtils.takeScreenshot(t, screenshotChange.getLeash(),
                 animationChange.getLeash(), cropBounds, Integer.MAX_VALUE);
     }
+
+    /** To provide an {@link Animation} based on the transition infos. */
+    private interface AnimationProvider {
+        Animation get(@NonNull TransitionInfo info, @NonNull TransitionInfo.Change change,
+                @NonNull Rect animationBounds);
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
index ad0dddf..eb6ac76 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/activityembedding/ActivityEmbeddingAnimationSpec.java
@@ -17,6 +17,9 @@
 package com.android.wm.shell.activityembedding;
 
 
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
+
 import android.content.Context;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -33,7 +36,6 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.internal.R;
 import com.android.internal.policy.TransitionAnimation;
 import com.android.wm.shell.transition.Transitions;
 
@@ -175,16 +177,20 @@
     }
 
     @NonNull
-    Animation loadOpenAnimation(@NonNull TransitionInfo.Change change,
-            @NonNull Rect wholeAnimationBounds) {
+    Animation loadOpenAnimation(@NonNull TransitionInfo info,
+            @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
         final boolean isEnter = Transitions.isOpeningType(change.getMode());
         final Animation animation;
-        // TODO(b/207070762):
-        // 1. Implement clearTop version: R.anim.task_fragment_clear_top_close_enter/exit
-        // 2. Implement edgeExtension version
-        animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
-                ? R.anim.task_fragment_open_enter
-                : R.anim.task_fragment_open_exit);
+        // TODO(b/207070762): Implement edgeExtension version
+        if (shouldShowBackdrop(info, change)) {
+            animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+                    ? com.android.internal.R.anim.task_fragment_clear_top_open_enter
+                    : com.android.internal.R.anim.task_fragment_clear_top_open_exit);
+        } else {
+            animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+                    ? com.android.internal.R.anim.task_fragment_open_enter
+                    : com.android.internal.R.anim.task_fragment_open_exit);
+        }
         // Use the whole animation bounds instead of the change bounds, so that when multiple change
         // targets are opening at the same time, the animation applied to each will be the same.
         // Otherwise, we may see gap between the activities that are launching together.
@@ -195,16 +201,20 @@
     }
 
     @NonNull
-    Animation loadCloseAnimation(@NonNull TransitionInfo.Change change,
-            @NonNull Rect wholeAnimationBounds) {
+    Animation loadCloseAnimation(@NonNull TransitionInfo info,
+            @NonNull TransitionInfo.Change change, @NonNull Rect wholeAnimationBounds) {
         final boolean isEnter = Transitions.isOpeningType(change.getMode());
         final Animation animation;
-        // TODO(b/207070762):
-        // 1. Implement clearTop version: R.anim.task_fragment_clear_top_close_enter/exit
-        // 2. Implement edgeExtension version
-        animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
-                ? R.anim.task_fragment_close_enter
-                : R.anim.task_fragment_close_exit);
+        // TODO(b/207070762): Implement edgeExtension version
+        if (shouldShowBackdrop(info, change)) {
+            animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+                    ? com.android.internal.R.anim.task_fragment_clear_top_close_enter
+                    : com.android.internal.R.anim.task_fragment_clear_top_close_exit);
+        } else {
+            animation = mTransitionAnimation.loadDefaultAnimationRes(isEnter
+                    ? com.android.internal.R.anim.task_fragment_close_enter
+                    : com.android.internal.R.anim.task_fragment_close_exit);
+        }
         // Use the whole animation bounds instead of the change bounds, so that when multiple change
         // targets are closing at the same time, the animation applied to each will be the same.
         // Otherwise, we may see gap between the activities that are finishing together.
@@ -213,4 +223,11 @@
         animation.scaleCurrentDuration(mTransitionAnimationScaleSetting);
         return animation;
     }
+
+    private boolean shouldShowBackdrop(@NonNull TransitionInfo info,
+            @NonNull TransitionInfo.Change change) {
+        final Animation a = loadAttributeAnimation(info, change, WALLPAPER_TRANSITION_NONE,
+                mTransitionAnimation);
+        return a != null && a.getShowBackdrop();
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 80cdd1f..c25bbbf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -29,6 +29,7 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.ProtoLogController;
+import com.android.wm.shell.R;
 import com.android.wm.shell.RootDisplayAreaOrganizer;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -173,6 +174,7 @@
     @WMSingleton
     @Provides
     static ShellTaskOrganizer provideShellTaskOrganizer(
+            Context context,
             ShellInit shellInit,
             ShellCommandHandler shellCommandHandler,
             CompatUIController compatUI,
@@ -180,6 +182,10 @@
             Optional<RecentTasksController> recentTasksOptional,
             @ShellMainThread ShellExecutor mainExecutor
     ) {
+        if (!context.getResources().getBoolean(R.bool.config_registerShellTaskOrganizerOnInit)) {
+            // TODO(b/238217847): Force override shell init if registration is disabled
+            shellInit = new ShellInit(mainExecutor);
+        }
         return new ShellTaskOrganizer(shellInit, shellCommandHandler, compatUI,
                 unfoldAnimationController, recentTasksOptional, mainExecutor);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index e784261d..37a50b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -188,14 +188,16 @@
             @ShellMainThread Choreographer mainChoreographer,
             ShellTaskOrganizer taskOrganizer,
             DisplayController displayController,
-            SyncTransactionQueue syncQueue) {
+            SyncTransactionQueue syncQueue,
+            @DynamicOverride DesktopModeController desktopModeController) {
         return new CaptionWindowDecorViewModel(
                         context,
                         mainHandler,
                         mainChoreographer,
                         taskOrganizer,
                         displayController,
-                        syncQueue);
+                        syncQueue,
+                        desktopModeController);
     }
 
     //
@@ -318,6 +320,7 @@
             ShellCommandHandler shellCommandHandler,
             ShellController shellController,
             DisplayController displayController,
+            PipAnimationController pipAnimationController,
             PipAppOpsListener pipAppOpsListener,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PhonePipKeepClearAlgorithm pipKeepClearAlgorithm,
@@ -337,11 +340,12 @@
             @ShellMainThread ShellExecutor mainExecutor) {
         return Optional.ofNullable(PipController.create(
                 context, shellInit, shellCommandHandler, shellController,
-                displayController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm,
-                pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController,
-                pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
-                windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
-                displayInsetsController, oneHandedController, mainExecutor));
+                displayController, pipAnimationController, pipAppOpsListener, pipBoundsAlgorithm,
+                pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, pipMediaController,
+                phonePipMenuController, pipTaskOrganizer, pipTransitionState, pipTouchHandler,
+                pipTransitionController, windowManagerShellWrapper, taskStackListener,
+                pipParamsChangedForwarder, displayInsetsController, oneHandedController,
+                mainExecutor));
     }
 
     @WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
index 9474cfe..99739c4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java
@@ -177,6 +177,25 @@
     }
 
     /**
+     * Turn desktop mode on or off
+     * @param active the desired state for desktop mode setting
+     */
+    public void setDesktopModeActive(boolean active) {
+        int value = active ? 1 : 0;
+        Settings.System.putInt(mContext.getContentResolver(), Settings.System.DESKTOP_MODE, value);
+    }
+
+    /**
+     * Returns the windowing mode of the display area with the specified displayId.
+     * @param displayId
+     * @return
+     */
+    public int getDisplayAreaWindowingMode(int displayId) {
+        return mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(displayId)
+                .configuration.windowConfiguration.getWindowingMode();
+    }
+
+    /**
      * A {@link ContentObserver} for listening to changes to {@link Settings.System#DESKTOP_MODE}
      */
     private final class SettingsObserver extends ContentObserver {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
index b32c3ee..6728c00 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipAnimationController.java
@@ -195,6 +195,17 @@
     }
 
     /**
+     * Returns true if the PiP window is currently being animated.
+     */
+    public boolean isAnimating() {
+        PipAnimationController.PipTransitionAnimator animator = getCurrentAnimator();
+        if (animator != null && animator.isRunning()) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Quietly cancel the animator by removing the listeners first.
      */
     static void quietCancel(@NonNull ValueAnimator animator) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 1a52d8c..f170e77 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -324,19 +324,6 @@
         return mPipTransitionController;
     }
 
-    /**
-     * Returns true if the PiP window is currently being animated.
-     */
-    public boolean isAnimating() {
-        // TODO(b/183746978) move this to PipAnimationController, and inject that in PipController
-        PipAnimationController.PipTransitionAnimator animator =
-                mPipAnimationController.getCurrentAnimator();
-        if (animator != null && animator.isRunning()) {
-            return true;
-        }
-        return false;
-    }
-
     public Rect getCurrentOrAnimatingBounds() {
         PipAnimationController.PipTransitionAnimator animator =
                 mPipAnimationController.getCurrentAnimator();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index bc8191d..af47666 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -130,6 +130,7 @@
     private DisplayController mDisplayController;
     private PipInputConsumer mPipInputConsumer;
     private WindowManagerShellWrapper mWindowManagerShellWrapper;
+    private PipAnimationController mPipAnimationController;
     private PipAppOpsListener mAppOpsListener;
     private PipMediaController mMediaController;
     private PipBoundsAlgorithm mPipBoundsAlgorithm;
@@ -158,7 +159,7 @@
             return;
         }
         // if there is another animation ongoing, wait for it to finish and try again
-        if (mPipTaskOrganizer.isAnimating()) {
+        if (mPipAnimationController.isAnimating()) {
             mMainExecutor.removeCallbacks(
                     mMovePipInResponseToKeepClearAreasChangeCallback);
             mMainExecutor.executeDelayed(
@@ -368,6 +369,7 @@
             ShellCommandHandler shellCommandHandler,
             ShellController shellController,
             DisplayController displayController,
+            PipAnimationController pipAnimationController,
             PipAppOpsListener pipAppOpsListener,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PipKeepClearAlgorithm pipKeepClearAlgorithm,
@@ -392,11 +394,12 @@
         }
 
         return new PipController(context, shellInit, shellCommandHandler, shellController,
-                displayController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm,
-                pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController,
-                pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
-                windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
-                displayInsetsController, oneHandedController, mainExecutor)
+                displayController, pipAnimationController, pipAppOpsListener,
+                pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper,
+                pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState,
+                pipTouchHandler, pipTransitionController, windowManagerShellWrapper,
+                taskStackListener, pipParamsChangedForwarder, displayInsetsController,
+                oneHandedController, mainExecutor)
                 .mImpl;
     }
 
@@ -405,6 +408,7 @@
             ShellCommandHandler shellCommandHandler,
             ShellController shellController,
             DisplayController displayController,
+            PipAnimationController pipAnimationController,
             PipAppOpsListener pipAppOpsListener,
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PipKeepClearAlgorithm pipKeepClearAlgorithm,
@@ -445,6 +449,7 @@
         mMediaController = pipMediaController;
         mMenuController = phonePipMenuController;
         mTouchHandler = pipTouchHandler;
+        mPipAnimationController = pipAnimationController;
         mAppOpsListener = pipAppOpsListener;
         mOneHandedController = oneHandedController;
         mPipTransitionController = pipTransitionController;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 4c927b6..dbb2948 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -18,13 +18,11 @@
 
 import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
 import static android.app.ActivityOptions.ANIM_CUSTOM;
-import static android.app.ActivityOptions.ANIM_FROM_STYLE;
 import static android.app.ActivityOptions.ANIM_NONE;
 import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS;
 import static android.app.ActivityOptions.ANIM_SCALE_UP;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
 import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE;
@@ -43,10 +41,11 @@
 import static android.view.WindowManager.TRANSIT_RELAUNCH;
 import static android.view.WindowManager.TRANSIT_TO_BACK;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
-import static android.view.WindowManager.transitTypeToString;
 import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_OWNER_THUMBNAIL;
 import static android.window.TransitionInfo.FLAG_CROSS_PROFILE_WORK_THUMBNAIL;
 import static android.window.TransitionInfo.FLAG_DISPLAY_HAS_ALERT_WINDOWS;
+import static android.window.TransitionInfo.FLAG_FILLS_TASK;
+import static android.window.TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY;
 import static android.window.TransitionInfo.FLAG_IS_DISPLAY;
 import static android.window.TransitionInfo.FLAG_IS_VOICE_INTERACTION;
 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER;
@@ -59,6 +58,10 @@
 import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
 import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_NONE;
 import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.addBackgroundToTransition;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.getTransitionBackgroundColorIfSet;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.loadAttributeAnimation;
+import static com.android.wm.shell.transition.TransitionAnimationHelper.sDisableCustomTaskAnimationProperty;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -74,7 +77,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Insets;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
@@ -84,7 +86,6 @@
 import android.hardware.HardwareBuffer;
 import android.os.Handler;
 import android.os.IBinder;
-import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.view.Choreographer;
@@ -122,21 +123,6 @@
 public class DefaultTransitionHandler implements Transitions.TransitionHandler {
     private static final int MAX_ANIMATION_DURATION = 3000;
 
-    /**
-     * Restrict ability of activities overriding transition animation in a way such that
-     * an activity can do it only when the transition happens within a same task.
-     *
-     * @see android.app.Activity#overridePendingTransition(int, int)
-     */
-    private static final String DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY =
-            "persist.wm.disable_custom_task_animation";
-
-    /**
-     * @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY
-     */
-    static boolean sDisableCustomTaskAnimationProperty =
-            SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true);
-
     private final TransactionPool mTransactionPool;
     private final DisplayController mDisplayController;
     private final Context mContext;
@@ -384,8 +370,10 @@
                         change.getEndAbsBounds().top - info.getRootOffset().y);
                 // Seamless display transition doesn't need to animate.
                 if (isSeamlessDisplayChange) continue;
-                if (isTask) {
-                    // Skip non-tasks since those usually have null bounds.
+                if (isTask || (change.hasFlags(FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)
+                        && !change.hasFlags(FLAG_FILLS_TASK))) {
+                    // Update Task and embedded split window crop bounds, otherwise we may see crop
+                    // on previous bounds during the rotation animation.
                     startTransaction.setWindowCrop(change.getLeash(),
                             change.getEndAbsBounds().width(), change.getEndAbsBounds().height());
                 }
@@ -431,22 +419,8 @@
                     cornerRadius = 0;
                 }
 
-                if (a.getShowBackdrop()) {
-                    if (info.getAnimationOptions().getBackgroundColor() != 0) {
-                        // If available use the background color provided through AnimationOptions
-                        backgroundColorForTransition =
-                                info.getAnimationOptions().getBackgroundColor();
-                    } else if (a.getBackdropColor() != 0) {
-                        // Otherwise fallback on the background color provided through the animation
-                        // definition.
-                        backgroundColorForTransition = a.getBackdropColor();
-                    } else if (change.getBackgroundColor() != 0) {
-                        // Otherwise default to the window's background color if provided through
-                        // the theme as the background color for the animation - the top most window
-                        // with a valid background color and showBackground set takes precedence.
-                        backgroundColorForTransition = change.getBackgroundColor();
-                    }
-                }
+                backgroundColorForTransition = getTransitionBackgroundColorIfSet(info, change, a,
+                        backgroundColorForTransition);
 
                 boolean delayedEdgeExtension = false;
                 if (!isTask && a.hasExtension()) {
@@ -668,29 +642,6 @@
         return edgeExtensionLayer;
     }
 
-    private void addBackgroundToTransition(
-            @NonNull SurfaceControl rootLeash,
-            @ColorInt int color,
-            @NonNull SurfaceControl.Transaction startTransaction,
-            @NonNull SurfaceControl.Transaction finishTransaction
-    ) {
-        final Color bgColor = Color.valueOf(color);
-        final float[] colorArray = new float[] { bgColor.red(), bgColor.green(), bgColor.blue() };
-
-        final SurfaceControl animationBackgroundSurface = new SurfaceControl.Builder()
-                .setName("Animation Background")
-                .setParent(rootLeash)
-                .setColorLayer()
-                .setOpaque(true)
-                .build();
-
-        startTransaction
-                .setLayer(animationBackgroundSurface, Integer.MIN_VALUE)
-                .setColor(animationBackgroundSurface, colorArray)
-                .show(animationBackgroundSurface);
-        finishTransaction.remove(animationBackgroundSurface);
-    }
-
     @Nullable
     @Override
     public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@@ -704,9 +655,9 @@
     }
 
     @Nullable
-    private Animation loadAnimation(TransitionInfo info, TransitionInfo.Change change,
-            int wallpaperTransit) {
-        Animation a = null;
+    private Animation loadAnimation(@NonNull TransitionInfo info,
+            @NonNull TransitionInfo.Change change, int wallpaperTransit) {
+        Animation a;
 
         final int type = info.getType();
         final int flags = info.getFlags();
@@ -717,12 +668,10 @@
         final boolean isTask = change.getTaskInfo() != null;
         final TransitionInfo.AnimationOptions options = info.getAnimationOptions();
         final int overrideType = options != null ? options.getType() : ANIM_NONE;
-        final boolean canCustomContainer = isTask ? !sDisableCustomTaskAnimationProperty : true;
+        final boolean canCustomContainer = !isTask || !sDisableCustomTaskAnimationProperty;
         final Rect endBounds = Transitions.isClosingType(changeMode)
                 ? mRotator.getEndBoundsInStartRotation(change)
                 : change.getEndAbsBounds();
-        final boolean isDream =
-                isTask && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_DREAM;
 
         if (info.isKeyguardGoingAway()) {
             a = mTransitionAnimation.loadKeyguardExitAnimation(flags,
@@ -763,87 +712,7 @@
             // This received a transferred starting window, so don't animate
             return null;
         } else {
-            int animAttr = 0;
-            boolean translucent = false;
-            if (isDream) {
-                if (type == TRANSIT_OPEN) {
-                    animAttr = enter
-                            ? R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation
-                            : R.styleable.WindowAnimation_dreamActivityOpenExitAnimation;
-                } else if (type == TRANSIT_CLOSE) {
-                    animAttr = enter
-                            ? 0
-                            : R.styleable.WindowAnimation_dreamActivityCloseExitAnimation;
-                }
-            } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
-                animAttr = enter
-                        ? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
-                        : R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
-            } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) {
-                animAttr = enter
-                        ? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
-                        : R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
-            } else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) {
-                animAttr = enter
-                        ? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
-                        : R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
-            } else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) {
-                animAttr = enter
-                        ? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
-                        : R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
-            } else if (type == TRANSIT_OPEN) {
-                // We will translucent open animation for translucent activities and tasks. Choose
-                // WindowAnimation_activityOpenEnterAnimation and set translucent here, then
-                // TransitionAnimation loads appropriate animation later.
-                if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
-                    translucent = true;
-                }
-                if (isTask && !translucent) {
-                    animAttr = enter
-                            ? R.styleable.WindowAnimation_taskOpenEnterAnimation
-                            : R.styleable.WindowAnimation_taskOpenExitAnimation;
-                } else {
-                    animAttr = enter
-                            ? R.styleable.WindowAnimation_activityOpenEnterAnimation
-                            : R.styleable.WindowAnimation_activityOpenExitAnimation;
-                }
-            } else if (type == TRANSIT_TO_FRONT) {
-                animAttr = enter
-                        ? R.styleable.WindowAnimation_taskToFrontEnterAnimation
-                        : R.styleable.WindowAnimation_taskToFrontExitAnimation;
-            } else if (type == TRANSIT_CLOSE) {
-                if (isTask) {
-                    animAttr = enter
-                            ? R.styleable.WindowAnimation_taskCloseEnterAnimation
-                            : R.styleable.WindowAnimation_taskCloseExitAnimation;
-                } else {
-                    if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) {
-                        translucent = true;
-                    }
-                    animAttr = enter
-                            ? R.styleable.WindowAnimation_activityCloseEnterAnimation
-                            : R.styleable.WindowAnimation_activityCloseExitAnimation;
-                }
-            } else if (type == TRANSIT_TO_BACK) {
-                animAttr = enter
-                        ? R.styleable.WindowAnimation_taskToBackEnterAnimation
-                        : R.styleable.WindowAnimation_taskToBackExitAnimation;
-            }
-
-            if (animAttr != 0) {
-                if (overrideType == ANIM_FROM_STYLE && canCustomContainer) {
-                    a = mTransitionAnimation
-                            .loadAnimationAttr(options.getPackageName(), options.getAnimations(),
-                                    animAttr, translucent);
-                } else {
-                    a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr, translucent);
-                }
-            }
-
-            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
-                    "loadAnimation: anim=%s animAttr=0x%x type=%s isEntrance=%b", a, animAttr,
-                    transitTypeToString(type),
-                    enter);
+            a = loadAttributeAnimation(info, change, wallpaperTransit, mTransitionAnimation);
         }
 
         if (a != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
new file mode 100644
index 0000000..efee6f40
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -0,0 +1,220 @@
+/*
+ * 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.wm.shell.transition;
+
+import static android.app.ActivityOptions.ANIM_FROM_STYLE;
+import static android.app.ActivityOptions.ANIM_NONE;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_DREAM;
+import static android.view.WindowManager.TRANSIT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_BACK;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static android.view.WindowManager.transitTypeToString;
+import static android.window.TransitionInfo.FLAG_TRANSLUCENT;
+
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_CLOSE;
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_CLOSE;
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_INTRA_OPEN;
+import static com.android.internal.policy.TransitionAnimation.WALLPAPER_TRANSITION_OPEN;
+
+import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.Color;
+import android.os.SystemProperties;
+import android.view.SurfaceControl;
+import android.view.animation.Animation;
+import android.window.TransitionInfo;
+
+import com.android.internal.R;
+import com.android.internal.policy.TransitionAnimation;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.protolog.ShellProtoLogGroup;
+
+/** The helper class that provides methods for adding styles to transition animations. */
+public class TransitionAnimationHelper {
+
+    /**
+     * Restrict ability of activities overriding transition animation in a way such that
+     * an activity can do it only when the transition happens within a same task.
+     *
+     * @see android.app.Activity#overridePendingTransition(int, int)
+     */
+    private static final String DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY =
+            "persist.wm.disable_custom_task_animation";
+
+    /**
+     * @see #DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY
+     */
+    static final boolean sDisableCustomTaskAnimationProperty =
+            SystemProperties.getBoolean(DISABLE_CUSTOM_TASK_ANIMATION_PROPERTY, true);
+
+    /** Loads the animation that is defined through attribute id for the given transition. */
+    @Nullable
+    public static Animation loadAttributeAnimation(@NonNull TransitionInfo info,
+            @NonNull TransitionInfo.Change change, int wallpaperTransit,
+            @NonNull TransitionAnimation transitionAnimation) {
+        final int type = info.getType();
+        final int changeMode = change.getMode();
+        final int changeFlags = change.getFlags();
+        final boolean enter = Transitions.isOpeningType(changeMode);
+        final boolean isTask = change.getTaskInfo() != null;
+        final TransitionInfo.AnimationOptions options = info.getAnimationOptions();
+        final int overrideType = options != null ? options.getType() : ANIM_NONE;
+        final boolean canCustomContainer = !isTask || !sDisableCustomTaskAnimationProperty;
+        final boolean isDream =
+                isTask && change.getTaskInfo().topActivityType == ACTIVITY_TYPE_DREAM;
+        int animAttr = 0;
+        boolean translucent = false;
+        if (isDream) {
+            if (type == TRANSIT_OPEN) {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation
+                        : R.styleable.WindowAnimation_dreamActivityOpenExitAnimation;
+            } else if (type == TRANSIT_CLOSE) {
+                animAttr = enter
+                        ? 0
+                        : R.styleable.WindowAnimation_dreamActivityCloseExitAnimation;
+            }
+        } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_OPEN) {
+            animAttr = enter
+                    ? R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation
+                    : R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
+        } else if (wallpaperTransit == WALLPAPER_TRANSITION_INTRA_CLOSE) {
+            animAttr = enter
+                    ? R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation
+                    : R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
+        } else if (wallpaperTransit == WALLPAPER_TRANSITION_OPEN) {
+            animAttr = enter
+                    ? R.styleable.WindowAnimation_wallpaperOpenEnterAnimation
+                    : R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
+        } else if (wallpaperTransit == WALLPAPER_TRANSITION_CLOSE) {
+            animAttr = enter
+                    ? R.styleable.WindowAnimation_wallpaperCloseEnterAnimation
+                    : R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
+        } else if (type == TRANSIT_OPEN) {
+            // We will translucent open animation for translucent activities and tasks. Choose
+            // WindowAnimation_activityOpenEnterAnimation and set translucent here, then
+            // TransitionAnimation loads appropriate animation later.
+            if ((changeFlags & FLAG_TRANSLUCENT) != 0 && enter) {
+                translucent = true;
+            }
+            if (isTask && !translucent) {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_taskOpenEnterAnimation
+                        : R.styleable.WindowAnimation_taskOpenExitAnimation;
+            } else {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_activityOpenEnterAnimation
+                        : R.styleable.WindowAnimation_activityOpenExitAnimation;
+            }
+        } else if (type == TRANSIT_TO_FRONT) {
+            animAttr = enter
+                    ? R.styleable.WindowAnimation_taskToFrontEnterAnimation
+                    : R.styleable.WindowAnimation_taskToFrontExitAnimation;
+        } else if (type == TRANSIT_CLOSE) {
+            if (isTask) {
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_taskCloseEnterAnimation
+                        : R.styleable.WindowAnimation_taskCloseExitAnimation;
+            } else {
+                if ((changeFlags & FLAG_TRANSLUCENT) != 0 && !enter) {
+                    translucent = true;
+                }
+                animAttr = enter
+                        ? R.styleable.WindowAnimation_activityCloseEnterAnimation
+                        : R.styleable.WindowAnimation_activityCloseExitAnimation;
+            }
+        } else if (type == TRANSIT_TO_BACK) {
+            animAttr = enter
+                    ? R.styleable.WindowAnimation_taskToBackEnterAnimation
+                    : R.styleable.WindowAnimation_taskToBackExitAnimation;
+        }
+
+        Animation a = null;
+        if (animAttr != 0) {
+            if (overrideType == ANIM_FROM_STYLE && canCustomContainer) {
+                a = transitionAnimation
+                        .loadAnimationAttr(options.getPackageName(), options.getAnimations(),
+                                animAttr, translucent);
+            } else {
+                a = transitionAnimation.loadDefaultAnimationAttr(animAttr, translucent);
+            }
+        }
+
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
+                "loadAnimation: anim=%s animAttr=0x%x type=%s isEntrance=%b", a, animAttr,
+                transitTypeToString(type),
+                enter);
+        return a;
+    }
+
+    /**
+     * Gets the background {@link ColorInt} for the given transition animation if it is set.
+     *
+     * @param defaultColor  {@link ColorInt} to return if there is no background color specified by
+     *                      the given transition animation.
+     */
+    @ColorInt
+    public static int getTransitionBackgroundColorIfSet(@NonNull TransitionInfo info,
+            @NonNull TransitionInfo.Change change, @NonNull Animation a,
+            @ColorInt int defaultColor) {
+        if (!a.getShowBackdrop()) {
+            return defaultColor;
+        }
+        if (info.getAnimationOptions() != null
+                && info.getAnimationOptions().getBackgroundColor() != 0) {
+            // If available use the background color provided through AnimationOptions
+            return info.getAnimationOptions().getBackgroundColor();
+        } else if (a.getBackdropColor() != 0) {
+            // Otherwise fallback on the background color provided through the animation
+            // definition.
+            return a.getBackdropColor();
+        } else if (change.getBackgroundColor() != 0) {
+            // Otherwise default to the window's background color if provided through
+            // the theme as the background color for the animation - the top most window
+            // with a valid background color and showBackground set takes precedence.
+            return change.getBackgroundColor();
+        }
+        return defaultColor;
+    }
+
+    /**
+     * Adds the given {@code backgroundColor} as the background color to the transition animation.
+     */
+    public static void addBackgroundToTransition(@NonNull SurfaceControl rootLeash,
+            @ColorInt int backgroundColor, @NonNull SurfaceControl.Transaction startTransaction,
+            @NonNull SurfaceControl.Transaction finishTransaction) {
+        if (backgroundColor == 0) {
+            // No background color.
+            return;
+        }
+        final Color bgColor = Color.valueOf(backgroundColor);
+        final float[] colorArray = new float[] { bgColor.red(), bgColor.green(), bgColor.blue() };
+        final SurfaceControl animationBackgroundSurface = new SurfaceControl.Builder()
+                .setName("Animation Background")
+                .setParent(rootLeash)
+                .setColorLayer()
+                .setOpaque(true)
+                .build();
+        startTransaction
+                .setLayer(animationBackgroundSurface, Integer.MIN_VALUE)
+                .setColor(animationBackgroundSurface, colorArray)
+                .show(animationBackgroundSurface);
+        finishTransaction.remove(animationBackgroundSurface);
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 8b36db920..9e49b51 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -37,6 +37,7 @@
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
 import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.desktopmode.DesktopModeController;
 import com.android.wm.shell.desktopmode.DesktopModeStatus;
 import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
 import com.android.wm.shell.transition.Transitions;
@@ -54,6 +55,7 @@
     private final DisplayController mDisplayController;
     private final SyncTransactionQueue mSyncQueue;
     private FreeformTaskTransitionStarter mTransitionStarter;
+    private DesktopModeController mDesktopModeController;
 
     public CaptionWindowDecorViewModel(
             Context context,
@@ -61,7 +63,8 @@
             Choreographer mainChoreographer,
             ShellTaskOrganizer taskOrganizer,
             DisplayController displayController,
-            SyncTransactionQueue syncQueue) {
+            SyncTransactionQueue syncQueue,
+            DesktopModeController desktopModeController) {
         mContext = context;
         mMainHandler = mainHandler;
         mMainChoreographer = mainChoreographer;
@@ -69,6 +72,7 @@
         mTaskOrganizer = taskOrganizer;
         mDisplayController = displayController;
         mSyncQueue = syncQueue;
+        mDesktopModeController = desktopModeController;
     }
 
     @Override
@@ -211,8 +215,10 @@
         }
 
         private void handleEventForMove(MotionEvent e) {
-            if (mTaskOrganizer.getRunningTaskInfo(mTaskId).getWindowingMode()
-                    == WINDOWING_MODE_FULLSCREEN) {
+            RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
+            int windowingMode =  mDesktopModeController
+                    .getDisplayAreaWindowingMode(taskInfo.displayId);
+            if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
                 return;
             }
             switch (e.getActionMasked()) {
@@ -230,8 +236,14 @@
                 case MotionEvent.ACTION_UP:
                 case MotionEvent.ACTION_CANCEL: {
                     int dragPointerIdx = e.findPointerIndex(mDragPointerId);
+                    int statusBarHeight = mDisplayController.getDisplayLayout(taskInfo.displayId)
+                            .stableInsets().top;
                     mDragResizeCallback.onDragResizeEnd(
                             e.getRawX(dragPointerIdx), e.getRawY(dragPointerIdx));
+                    if (e.getRawY(dragPointerIdx) <= statusBarHeight
+                            && windowingMode == WINDOWING_MODE_FREEFORM) {
+                        mDesktopModeController.setDesktopModeActive(false);
+                    }
                     break;
                 }
             }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index a8d3bdc..1e08f1e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -48,6 +48,7 @@
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.onehanded.OneHandedController;
+import com.android.wm.shell.pip.PipAnimationController;
 import com.android.wm.shell.pip.PipAppOpsListener;
 import com.android.wm.shell.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.pip.PipBoundsState;
@@ -85,6 +86,7 @@
     @Mock private ShellCommandHandler mMockShellCommandHandler;
     @Mock private DisplayController mMockDisplayController;
     @Mock private PhonePipMenuController mMockPhonePipMenuController;
+    @Mock private PipAnimationController mMockPipAnimationController;
     @Mock private PipAppOpsListener mMockPipAppOpsListener;
     @Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
     @Mock private PhonePipKeepClearAlgorithm mMockPipKeepClearAlgorithm;
@@ -117,8 +119,8 @@
         mShellController = spy(new ShellController(mShellInit, mMockShellCommandHandler,
                 mMockExecutor));
         mPipController = new PipController(mContext, mShellInit, mMockShellCommandHandler,
-                mShellController, mMockDisplayController, mMockPipAppOpsListener,
-                mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
+                mShellController, mMockDisplayController, mMockPipAnimationController,
+                mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
                 mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
                 mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
                 mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
@@ -183,8 +185,8 @@
 
         ShellInit shellInit = new ShellInit(mMockExecutor);
         assertNull(PipController.create(spyContext, shellInit, mMockShellCommandHandler,
-                mShellController, mMockDisplayController, mMockPipAppOpsListener,
-                mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
+                mShellController, mMockDisplayController, mMockPipAnimationController,
+                mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm,
                 mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
                 mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
                 mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 2aca41e..8e350d5 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -53,8 +53,12 @@
 }
 
 MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
-    // TODO: Figure out why this workaround is needed, see b/13913604
-    // In the meantime this matches the behavior of GLRenderer, so it is not a regression
+    // In case the surface was destroyed (e.g. a previous trimMemory call) we
+    // need to recreate it here.
+    if (!isSurfaceReady() && mNativeWindow) {
+        setSurface(mNativeWindow.get(), mSwapBehavior);
+    }
+
     EGLint error = 0;
     if (!mEglManager.makeCurrent(mEglSurface, &error)) {
         return MakeCurrentResult::AlreadyCurrent;
@@ -166,6 +170,9 @@
 }
 
 bool SkiaOpenGLPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior) {
+    mNativeWindow = surface;
+    mSwapBehavior = swapBehavior;
+
     if (mEglSurface != EGL_NO_SURFACE) {
         mEglManager.destroySurface(mEglSurface);
         mEglSurface = EGL_NO_SURFACE;
@@ -182,7 +189,8 @@
 
     if (mEglSurface != EGL_NO_SURFACE) {
         const bool preserveBuffer = (swapBehavior != SwapBehavior::kSwap_discardBuffer);
-        mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
+        const bool isPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
+        ALOGE_IF(preserveBuffer != isPreserved, "Unable to match the desired swap behavior.");
         return true;
     }
 
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 186998a0..a80c613 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -61,7 +61,8 @@
 private:
     renderthread::EglManager& mEglManager;
     EGLSurface mEglSurface = EGL_NO_SURFACE;
-    bool mBufferPreserved = false;
+    sp<ANativeWindow> mNativeWindow;
+    renderthread::SwapBehavior mSwapBehavior = renderthread::SwapBehavior::kSwap_discardBuffer;
 };
 
 } /* namespace skiapipeline */
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 905d46e..cc2565d 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -55,7 +55,12 @@
 }
 
 MakeCurrentResult SkiaVulkanPipeline::makeCurrent() {
-    return MakeCurrentResult::AlreadyCurrent;
+    // In case the surface was destroyed (e.g. a previous trimMemory call) we
+    // need to recreate it here.
+    if (!isSurfaceReady() && mNativeWindow) {
+        setSurface(mNativeWindow.get(), SwapBehavior::kSwap_default);
+    }
+    return isContextReady() ? MakeCurrentResult::AlreadyCurrent : MakeCurrentResult::Failed;
 }
 
 Frame SkiaVulkanPipeline::getFrame() {
@@ -130,7 +135,11 @@
 
 void SkiaVulkanPipeline::onStop() {}
 
-bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior swapBehavior) {
+// We can safely ignore the swap behavior because VkManager will always operate
+// in a mode equivalent to EGLManager::SwapBehavior::kBufferAge
+bool SkiaVulkanPipeline::setSurface(ANativeWindow* surface, SwapBehavior /*swapBehavior*/) {
+    mNativeWindow = surface;
+
     if (mVkSurface) {
         vulkanManager().destroySurface(mVkSurface);
         mVkSurface = nullptr;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index ada6af6..a6e685d 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -61,6 +61,7 @@
     renderthread::VulkanManager& vulkanManager();
 
     renderthread::VulkanSurface* mVkSurface = nullptr;
+    sp<ANativeWindow> mNativeWindow;
 };
 
 } /* namespace skiapipeline */
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 60ae604..7419f8f 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -404,7 +404,9 @@
     EXPECT_TRUE(pipeline->isSurfaceReady());
     renderThread.destroyRenderingContext();
     EXPECT_FALSE(pipeline->isSurfaceReady());
-    LOG_ALWAYS_FATAL_IF(pipeline->isSurfaceReady());
+
+    pipeline->makeCurrent();
+    EXPECT_TRUE(pipeline->isSurfaceReady());
 }
 
 RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, pictureCallback) {
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 1ebdc27..795af8a 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -300,7 +300,7 @@
         auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats;
 
         for (const auto& [surfaceControl, latchTime, acquireTimeOrFence, presentFence,
-                          previousReleaseFence, transformHint, frameEvents] : surfaceControlStats) {
+                  previousReleaseFence, transformHint, frameEvents, ignore] : surfaceControlStats) {
             ASurfaceControl* aSurfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
             aSurfaceControlStats[aSurfaceControl].acquireTimeOrFence = acquireTimeOrFence;
             aSurfaceControlStats[aSurfaceControl].previousReleaseFence = previousReleaseFence;
@@ -650,7 +650,7 @@
 
                 auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats;
                 for (const auto& [surfaceControl, latchTime, acquireTimeOrFence, presentFence,
-                                  previousReleaseFence, transformHint, frameEvents] :
+                              previousReleaseFence, transformHint, frameEvents, ignore] :
                      surfaceControlStats) {
                     ASurfaceControl* aSurfaceControl =
                             reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index b6eb82e..98cc18e 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -247,7 +247,7 @@
     <string name="adb_paired_devices_title" msgid="5268997341526217362">"Appareils associés"</string>
     <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Actuellement connecté"</string>
     <string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Infos sur l\'appareil"</string>
-    <string name="adb_device_forget" msgid="193072400783068417">"Retirer"</string>
+    <string name="adb_device_forget" msgid="193072400783068417">"Supprimer"</string>
     <string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Empreinte de l\'appareil : <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
     <string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Échec de la connexion"</string>
     <string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Vérifiez que l\'appareil <xliff:g id="DEVICE_NAME">%1$s</xliff:g> est connecté au bon réseau"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 7927c5d..eb53ea1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -758,16 +758,23 @@
     }
 
     public boolean isBusy() {
-        synchronized (mProfileLock) {
-            for (LocalBluetoothProfile profile : mProfiles) {
-                int status = getProfileConnectionState(profile);
-                if (status == BluetoothProfile.STATE_CONNECTING
-                        || status == BluetoothProfile.STATE_DISCONNECTING) {
-                    return true;
-                }
+        for (CachedBluetoothDevice memberDevice : getMemberDevice()) {
+            if (isBusyState(memberDevice)) {
+                return true;
             }
-            return getBondState() == BluetoothDevice.BOND_BONDING;
         }
+        return isBusyState(this);
+    }
+
+    private boolean isBusyState(CachedBluetoothDevice device){
+        for (LocalBluetoothProfile profile : device.getProfiles()) {
+            int status = device.getProfileConnectionState(profile);
+            if (status == BluetoothProfile.STATE_CONNECTING
+                    || status == BluetoothProfile.STATE_DISCONNECTING) {
+                return true;
+            }
+        }
+        return device.getBondState() == BluetoothDevice.BOND_BONDING;
     }
 
     private boolean updateProfiles() {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 79e9938..315ab0a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -1069,4 +1069,80 @@
         assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice);
         assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
     }
+
+    @Test
+    public void isBusy_mainDeviceIsConnecting_returnsBusy() {
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateSubDeviceProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mSubDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTING);
+
+        assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
+        assertThat(mCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mSubCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mCachedDevice.isBusy()).isTrue();
+    }
+
+    @Test
+    public void isBusy_mainDeviceIsBonding_returnsBusy() {
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateSubDeviceProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mSubDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING);
+
+        assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
+        assertThat(mCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mSubCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mCachedDevice.isBusy()).isTrue();
+    }
+
+    @Test
+    public void isBusy_memberDeviceIsConnecting_returnsBusy() {
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateSubDeviceProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mSubDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+
+        updateSubDeviceProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTING);
+
+        assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
+        assertThat(mCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mSubCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mCachedDevice.isBusy()).isTrue();
+    }
+
+    @Test
+    public void isBusy_memberDeviceIsBonding_returnsBusy() {
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateSubDeviceProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+
+        when(mSubDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDING);
+
+        assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
+        assertThat(mCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mSubCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mCachedDevice.isBusy()).isTrue();
+    }
+
+    @Test
+    public void isBusy_allDevicesAreNotBusy_returnsNotBusy() {
+        mCachedDevice.addMemberDevice(mSubCachedDevice);
+        updateProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        updateSubDeviceProfileStatus(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+        when(mSubDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+
+        assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
+        assertThat(mCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mSubCachedDevice.getProfiles().contains(mA2dpProfile)).isTrue();
+        assertThat(mCachedDevice.isBusy()).isFalse();
+    }
 }
diff --git a/packages/SystemUI/TEST_MAPPING b/packages/SystemUI/TEST_MAPPING
index 26feaf9..cd45b8ea 100644
--- a/packages/SystemUI/TEST_MAPPING
+++ b/packages/SystemUI/TEST_MAPPING
@@ -1,25 +1,6 @@
 {
   // Looking for unit test presubmit configuration?
   // This currently lives in ATP config apct/system_ui/unit_test
-  "presubmit-large": [
-    {
-      "name": "PlatformScenarioTests",
-      "options": [
-        {
-            "include-filter": "android.platform.test.scenario.sysui"
-        },
-        {
-            "include-annotation": "android.platform.test.scenario.annotation.Scenario"
-        },
-        {
-            "exclude-annotation": "org.junit.Ignore"
-        },
-        {
-            "exclude-annotation": "android.platform.test.annotations.Postsubmit"
-        }
-      ]
-    }
-  ],
   "presubmit-sysui": [
     {
       "name": "PlatformScenarioTests",
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java
index 1237259..506ccf3 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/NavigationEdgeBackPlugin.java
@@ -61,5 +61,13 @@
 
         /** Indicates that the gesture was cancelled and the system should not go back. */
         void cancelBack();
+
+        /**
+         * Indicates if back will be triggered if committed in current state.
+         *
+         * @param triggerBack if back will be triggered in current state.
+         */
+        // TODO(b/247883311): Remove default impl once SwipeBackGestureHandler overrides this.
+        default void setTriggerBack(boolean triggerBack) {}
     }
 }
diff --git a/packages/SystemUI/res/values-es/tiles_states_strings.xml b/packages/SystemUI/res/values-es/tiles_states_strings.xml
index 8d5c3c6..d7a8133 100644
--- a/packages/SystemUI/res/values-es/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es/tiles_states_strings.xml
@@ -58,12 +58,12 @@
   </string-array>
   <string-array name="tile_states_flashlight">
     <item msgid="3465257127433353857">"No disponible"</item>
-    <item msgid="5044688398303285224">"Desactivada"</item>
+    <item msgid="5044688398303285224">"Desactivado"</item>
     <item msgid="8527389108867454098">"Activado"</item>
   </string-array>
   <string-array name="tile_states_rotation">
     <item msgid="4578491772376121579">"No disponible"</item>
-    <item msgid="5776427577477729185">"Desactivada"</item>
+    <item msgid="5776427577477729185">"Desactivado"</item>
     <item msgid="7105052717007227415">"Activado"</item>
   </string-array>
   <string-array name="tile_states_bt">
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 4e97b48..01aabee 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -962,6 +962,6 @@
     <string name="bt_le_audio_broadcast_dialog_different_output" msgid="7885102097302562674">"Endre utgang"</string>
     <string name="bt_le_audio_broadcast_dialog_unknown_name" msgid="3791472237793443044">"Ukjent"</string>
     <string name="dream_date_complication_date_format" msgid="8191225366513860104">"EEE d. MMM"</string>
-    <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"t:mm"</string>
-    <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"tt:mm"</string>
+    <string name="dream_time_complication_12_hr_time_format" msgid="4691197486690291529">"h:mm"</string>
+    <string name="dream_time_complication_24_hr_time_format" msgid="6248280719733640813">"kk:mm"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 8084254..f22e797 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -131,6 +131,9 @@
     <!-- For StatusIconContainer to tag its icon views -->
     <item type="id" name="status_bar_view_state_tag" />
 
+    <!-- Status bar -->
+    <item type="id" name="status_bar_dot" />
+
     <!-- Default display cutout on the physical top of screen -->
     <item type="id" name="display_cutout" />
     <item type="id" name="display_cutout_left" />
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
index c7d5ffe..023ef31 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
@@ -217,12 +217,16 @@
                 unregisterSamplingListener();
                 mSamplingListenerRegistered = true;
                 SurfaceControl wrappedStopLayer = wrap(stopLayerControl);
+
+                // pass this to background thread to avoid empty Rect race condition
+                final Rect boundsCopy = new Rect(mSamplingRequestBounds);
+
                 mBackgroundExecutor.execute(() -> {
                     if (wrappedStopLayer != null && !wrappedStopLayer.isValid()) {
                         return;
                     }
                     mCompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
-                            wrappedStopLayer, mSamplingRequestBounds);
+                            wrappedStopLayer, boundsCopy);
                 });
                 mRegisteredSamplingBounds.set(mSamplingRequestBounds);
                 mRegisteredStopLayer = stopLayerControl;
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 67b683e..2e13903 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -455,6 +455,7 @@
                     }
                 }
 
+                boolean needToUpdateProviderViews = false;
                 final String newUniqueId = mDisplayInfo.uniqueId;
                 if (!Objects.equals(newUniqueId, mDisplayUniqueId)) {
                     mDisplayUniqueId = newUniqueId;
@@ -472,6 +473,37 @@
                         setupDecorations();
                         return;
                     }
+
+                    if (mScreenDecorHwcLayer != null) {
+                        updateHwLayerRoundedCornerDrawable();
+                        updateHwLayerRoundedCornerExistAndSize();
+                    }
+                    needToUpdateProviderViews = true;
+                }
+
+                final float newRatio = getPhysicalPixelDisplaySizeRatio();
+                if (mRoundedCornerResDelegate.getPhysicalPixelDisplaySizeRatio() != newRatio) {
+                    mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(newRatio);
+                    if (mScreenDecorHwcLayer != null) {
+                        updateHwLayerRoundedCornerExistAndSize();
+                    }
+                    needToUpdateProviderViews = true;
+                }
+
+                if (needToUpdateProviderViews) {
+                    updateOverlayProviderViews(null);
+                } else {
+                    updateOverlayProviderViews(new Integer[] {
+                            mFaceScanningViewId,
+                            R.id.display_cutout,
+                            R.id.display_cutout_left,
+                            R.id.display_cutout_right,
+                            R.id.display_cutout_bottom,
+                    });
+                }
+
+                if (mScreenDecorHwcLayer != null) {
+                    mScreenDecorHwcLayer.onDisplayChanged(newUniqueId);
                 }
             }
         };
@@ -1037,8 +1069,6 @@
                 && (newRotation != mRotation || displayModeChanged(mDisplayMode, newMod))) {
             mRotation = newRotation;
             mDisplayMode = newMod;
-            mRoundedCornerResDelegate.setPhysicalPixelDisplaySizeRatio(
-                    getPhysicalPixelDisplaySizeRatio());
             if (mScreenDecorHwcLayer != null) {
                 mScreenDecorHwcLayer.pendingConfigChange = false;
                 mScreenDecorHwcLayer.updateRotation(mRotation);
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
index 3d5e601..e342ac2 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
@@ -47,7 +47,8 @@
             shareIntent.putExtra(Intent.EXTRA_STREAM, clipData.getItemAt(0).getUri());
             shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
         } else {
-            shareIntent.putExtra(Intent.EXTRA_TEXT, clipData.getItemAt(0).coerceToText(context));
+            shareIntent.putExtra(
+                    Intent.EXTRA_TEXT, clipData.getItemAt(0).coerceToText(context).toString());
             shareIntent.setType("text/plain");
         }
         Intent chooserIntent = Intent.createChooser(shareIntent, null)
diff --git a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
index 8b4aeef..a252864 100644
--- a/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
+++ b/packages/SystemUI/src/com/android/systemui/decor/RoundedCornerResDelegate.kt
@@ -78,18 +78,23 @@
         reloadMeasures()
     }
 
+    private fun reloadAll(newReloadToken: Int) {
+        if (reloadToken == newReloadToken) {
+            return
+        }
+        reloadToken = newReloadToken
+        reloadRes()
+        reloadMeasures()
+    }
+
     fun updateDisplayUniqueId(newDisplayUniqueId: String?, newReloadToken: Int?) {
         if (displayUniqueId != newDisplayUniqueId) {
             displayUniqueId = newDisplayUniqueId
             newReloadToken ?.let { reloadToken = it }
             reloadRes()
             reloadMeasures()
-        } else if (newReloadToken != null) {
-            if (reloadToken == newReloadToken) {
-                return
-            }
-            reloadToken = newReloadToken
-            reloadMeasures()
+        } else {
+            newReloadToken?.let { reloadAll(it) }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
index 6f38f4f..5f96a3b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardUnlockAnimationController.kt
@@ -285,6 +285,14 @@
     var willUnlockWithInWindowLauncherAnimations: Boolean = false
 
     /**
+     * Whether we called [ILauncherUnlockAnimationController.prepareForUnlock], but have not yet
+     * called [ILauncherUnlockAnimationController.playUnlockAnimation]. This is used exclusively for
+     * logging purposes to help track down bugs where the Launcher surface is prepared for unlock
+     * but then never animated.
+     */
+    private var launcherPreparedForUnlock = false
+
+    /**
      * Whether we decided in [prepareForInWindowLauncherAnimations] that we are able to and want to
      * play the smartspace shared element animation. If true,
      * [willUnlockWithInWindowLauncherAnimations] will also always be true since in-window
@@ -376,6 +384,20 @@
     }
 
     /**
+     * Logging helper to log the conditions under which we decide to perform the in-window
+     * animations. This is used if we prepare to unlock but then somehow decide later to not play
+     * the animation, which would leave Launcher in a bad state.
+     */
+    private fun logInWindowAnimationConditions() {
+        Log.wtf(TAG, "canPerformInWindowLauncherAnimations expected all of these to be true: ")
+        Log.wtf(TAG, "  isNexusLauncherUnderneath: ${isNexusLauncherUnderneath()}")
+        Log.wtf(TAG, "  !notificationShadeWindowController.isLaunchingActivity: " +
+                "${!notificationShadeWindowController.isLaunchingActivity}")
+        Log.wtf(TAG, "  launcherUnlockController != null: ${launcherUnlockController != null}")
+        Log.wtf(TAG, "  !isFoldable(context): ${!isFoldable(context)}")
+    }
+
+    /**
      * Called from [KeyguardStateController] to let us know that the keyguard going away state has
      * changed.
      */
@@ -384,6 +406,15 @@
                 !statusBarStateController.leaveOpenOnKeyguardHide()) {
             prepareForInWindowLauncherAnimations()
         }
+
+        // If the keyguard is no longer going away and we were unlocking with in-window animations,
+        // make sure that we've left the launcher at 100% unlocked. This is a fail-safe to prevent
+        // against "tiny launcher" and similar states where the launcher is left in the prepared to
+        // animate state.
+        if (!keyguardStateController.isKeyguardGoingAway &&
+                willUnlockWithInWindowLauncherAnimations) {
+            launcherUnlockController?.setUnlockAmount(1f, true /* forceIfAnimating */)
+        }
     }
 
     /**
@@ -437,6 +468,8 @@
                 lockscreenSmartspaceBounds, /* lockscreenSmartspaceBounds */
                 selectedPage /* selectedPage */
             )
+
+            launcherPreparedForUnlock = true
         } catch (e: RemoteException) {
             Log.e(TAG, "Remote exception in prepareForInWindowUnlockAnimations.", e)
         }
@@ -495,6 +528,8 @@
                         true,
                         UNLOCK_ANIMATION_DURATION_MS + CANNED_UNLOCK_START_DELAY,
                         0 /* startDelay */)
+
+                launcherPreparedForUnlock = false
             } else {
                 // Otherwise, we're swiping in an app and should just fade it in. The swipe gesture
                 // will translate it until the end of the swipe gesture.
@@ -554,6 +589,12 @@
                 surfaceBehindEntryAnimator.start()
             }
         }
+
+        if (launcherPreparedForUnlock && !willUnlockWithInWindowLauncherAnimations) {
+            Log.wtf(TAG, "Launcher is prepared for unlock, so we should have started the " +
+                    "in-window animation, however we apparently did not.")
+            logInWindowAnimationConditions()
+        }
     }
 
     /**
@@ -569,6 +610,8 @@
             LAUNCHER_ICONS_ANIMATION_DURATION_MS /* duration */,
             CANNED_UNLOCK_START_DELAY /* startDelay */)
 
+        launcherPreparedForUnlock = false
+
         // Now that the Launcher surface (with its smartspace positioned identically to ours) is
         // visible, hide our smartspace.
         lockscreenSmartspace?.visibility = View.INVISIBLE
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index f8c6a57..8368792 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -149,32 +149,6 @@
                 }
             }
         }
-
-    companion object {
-        private const val SQUISHINESS_SCALE_START = 0.5
-        private const val SQUISHINESS_SCALE_FACTOR = 0.5
-        private fun getSquishinessScale(squishinessFraction: Float): Double {
-            return SQUISHINESS_SCALE_START + SQUISHINESS_SCALE_FACTOR * squishinessFraction
-        }
-    }
-
-    var squishinessFraction: Float = 1f
-        set(value) {
-            if (field == value) {
-                return
-            }
-            field = value
-
-            val scale = getSquishinessScale(field)
-            for (mediaPlayer in MediaPlayerData.players()) {
-                mediaPlayer.mediaViewHolder?.let {
-                    it.player.bottom = it.player.top + (scale * it.player.measuredHeight).toInt()
-                } ?: mediaPlayer.recommendationViewHolder?.let {
-                    it.recommendations.bottom = it.recommendations.top +
-                            (scale * it.recommendations.measuredHeight).toInt()
-                }
-            }
-        }
     private val configListener = object : ConfigurationController.ConfigurationListener {
         override fun onDensityOrFontScaleChanged() {
             // System font changes should only happen when UMO is offscreen or a flicker may occur
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index d605c1a..0f1338e 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -303,6 +303,13 @@
                     mOverviewProxyService.notifyBackAction(false, (int) mDownPoint.x,
                             (int) mDownPoint.y, false /* isButton */, !mIsOnLeftEdge);
                 }
+
+                @Override
+                public void setTriggerBack(boolean triggerBack) {
+                    if (mBackAnimation != null) {
+                        mBackAnimation.setTriggerBack(triggerBack);
+                    }
+                }
             };
 
     private final SysUiState.SysUiStateCallback mSysUiStateCallback =
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
index 122852f..24efc76 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/NavigationBarEdgePanel.java
@@ -880,6 +880,7 @@
             // Whenever the trigger back state changes the existing translation animation should be
             // cancelled
             mTranslationAnimation.cancel();
+            mBackCallback.setTriggerBack(mTriggerBack);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index f41b905..18bd6b7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -27,7 +27,6 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.media.MediaCarouselController;
 import com.android.systemui.media.MediaHierarchyManager;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.media.MediaHostState;
@@ -76,14 +75,13 @@
             @Named(QS_USING_MEDIA_PLAYER) boolean usingMediaPlayer,
             @Named(QS_PANEL) MediaHost mediaHost,
             QSTileRevealController.Factory qsTileRevealControllerFactory,
-            DumpManager dumpManager, MediaCarouselController mediaCarouselController,
-            MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
+            DumpManager dumpManager, MetricsLogger metricsLogger, UiEventLogger uiEventLogger,
             QSLogger qsLogger, BrightnessController.Factory brightnessControllerFactory,
             BrightnessSliderController.Factory brightnessSliderFactory,
             FalsingManager falsingManager,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager) {
         super(view, qstileHost, qsCustomizerController, usingMediaPlayer, mediaHost,
-                metricsLogger, uiEventLogger, qsLogger, dumpManager, mediaCarouselController);
+                metricsLogger, uiEventLogger, qsLogger, dumpManager);
         mTunerService = tunerService;
         mQsCustomizerController = qsCustomizerController;
         mQsTileRevealControllerFactory = qsTileRevealControllerFactory;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index a5c60a4..ded466a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -32,7 +32,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.Dumpable;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.media.MediaCarouselController;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTileView;
@@ -71,7 +70,6 @@
     private final UiEventLogger mUiEventLogger;
     private final QSLogger mQSLogger;
     private final DumpManager mDumpManager;
-    private final MediaCarouselController mMediaCarouselController;
     protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
     protected boolean mShouldUseSplitNotificationShade;
 
@@ -133,8 +131,7 @@
             MetricsLogger metricsLogger,
             UiEventLogger uiEventLogger,
             QSLogger qsLogger,
-            DumpManager dumpManager,
-            MediaCarouselController mediaCarouselController
+            DumpManager dumpManager
     ) {
         super(view);
         mHost = host;
@@ -147,7 +144,6 @@
         mDumpManager = dumpManager;
         mShouldUseSplitNotificationShade =
                 LargeScreenUtils.shouldUseSplitNotificationShade(getResources());
-        mMediaCarouselController = mediaCarouselController;
     }
 
     @Override
@@ -165,7 +161,6 @@
 
     public void setSquishinessFraction(float squishinessFraction) {
         mView.setSquishinessFraction(squishinessFraction);
-        mMediaCarouselController.setSquishinessFraction(squishinessFraction);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
index bd75c75..ae6ed20 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
@@ -444,7 +444,7 @@
         mShouldUseSettingsButton.set(false);
         mBgHandler.post(() -> {
             String settingsButtonText = getSettingsButton();
-            final View dialogView = createDialogView();
+            final View dialogView = createDialogView(quickSettingsContext);
             mMainHandler.post(() -> {
                 mDialog = new SystemUIDialog(quickSettingsContext, 0);
                 mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
@@ -469,14 +469,14 @@
     }
 
     @VisibleForTesting
-    View createDialogView() {
+    View createDialogView(Context quickSettingsContext) {
         if (mSecurityController.isParentalControlsEnabled()) {
             return createParentalControlsDialogView();
         }
-        return createOrganizationDialogView();
+        return createOrganizationDialogView(quickSettingsContext);
     }
 
-    private View createOrganizationDialogView() {
+    private View createOrganizationDialogView(Context quickSettingsContext) {
         final boolean isDeviceManaged = mSecurityController.isDeviceManaged();
         final boolean hasWorkProfile = mSecurityController.hasWorkProfile();
         final CharSequence deviceOwnerOrganization =
@@ -487,7 +487,7 @@
         final String vpnName = mSecurityController.getPrimaryVpnName();
         final String vpnNameWorkProfile = mSecurityController.getWorkProfileVpnName();
 
-        View dialogView = LayoutInflater.from(mContext)
+        View dialogView = LayoutInflater.from(quickSettingsContext)
                 .inflate(R.layout.quick_settings_footer_dialog, null, false);
 
         // device management section
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 7ce0ad0..9739974 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -26,7 +26,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.R;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.media.MediaCarouselController;
 import com.android.systemui.media.MediaHierarchyManager;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.plugins.qs.QSTile;
@@ -56,10 +55,10 @@
             @Named(QS_USING_COLLAPSED_LANDSCAPE_MEDIA)
                     Provider<Boolean> usingCollapsedLandscapeMediaProvider,
             MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
-            DumpManager dumpManager, MediaCarouselController mediaCarouselController
+            DumpManager dumpManager
     ) {
         super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
-                uiEventLogger, qsLogger, dumpManager, mediaCarouselController);
+                uiEventLogger, qsLogger, dumpManager);
         mUsingCollapsedLandscapeMediaProvider = usingCollapsedLandscapeMediaProvider;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
index b585961..ccaab1a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeaderController.java
@@ -30,6 +30,7 @@
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
 import com.android.systemui.statusbar.phone.StatusIconContainer;
 import com.android.systemui.statusbar.policy.Clock;
 import com.android.systemui.statusbar.policy.VariableDateViewController;
@@ -104,7 +105,7 @@
                 mView.requireViewById(R.id.date_clock)
         );
 
-        mIconManager = tintedIconManagerFactory.create(mIconContainer);
+        mIconManager = tintedIconManagerFactory.create(mIconContainer, StatusBarLocation.QS);
         mDemoModeReceiver = new ClockDemoModeReceiver(mClockView);
         mColorExtractor = colorExtractor;
         mOnColorsChangedListener = (extractor, which) -> {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
index fe40d4c..d3ed474 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
@@ -48,6 +48,7 @@
 import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.QS_HEADER_CONSTRAINT
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
 import com.android.systemui.statusbar.phone.StatusBarIconController
+import com.android.systemui.statusbar.phone.StatusBarLocation
 import com.android.systemui.statusbar.phone.StatusIconContainer
 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
 import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.LARGE_SCREEN_BATTERY_CONTROLLER
@@ -261,7 +262,7 @@
         batteryMeterViewController.ignoreTunerUpdates()
         batteryIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
 
-        iconManager = tintedIconManagerFactory.create(iconContainer)
+        iconManager = tintedIconManagerFactory.create(iconContainer, StatusBarLocation.QS)
         iconManager.setTint(
             Utils.getColorAttrDefaultColor(header.context, android.R.attr.textColorPrimary)
         )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 827d0d0f..c35c5c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -22,6 +22,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
+import android.annotation.IntDef;
 import android.app.ActivityManager;
 import android.app.Notification;
 import android.content.Context;
@@ -59,6 +60,8 @@
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.util.drawable.DrawableSize;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.text.NumberFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -86,6 +89,10 @@
     public static final int STATE_DOT = 1;
     public static final int STATE_HIDDEN = 2;
 
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({STATE_ICON, STATE_DOT, STATE_HIDDEN})
+    public @interface VisibleState { }
+
     private static final String TAG = "StatusBarIconView";
     private static final Property<StatusBarIconView, Float> ICON_APPEAR_AMOUNT
             = new FloatProperty<StatusBarIconView>("iconAppearAmount") {
@@ -133,6 +140,7 @@
     private final Paint mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private float mDotRadius;
     private int mStaticDotRadius;
+    @StatusBarIconView.VisibleState
     private int mVisibleState = STATE_ICON;
     private float mIconAppearAmount = 1.0f;
     private ObjectAnimator mIconAppearAnimator;
@@ -746,11 +754,12 @@
     }
 
     @Override
-    public void setVisibleState(int state) {
+    public void setVisibleState(@StatusBarIconView.VisibleState int state) {
         setVisibleState(state, true /* animate */, null /* endRunnable */);
     }
 
-    public void setVisibleState(int state, boolean animate) {
+    @Override
+    public void setVisibleState(@StatusBarIconView.VisibleState int state, boolean animate) {
         setVisibleState(state, animate, null);
     }
 
@@ -862,6 +871,7 @@
         return mIconAppearAmount;
     }
 
+    @StatusBarIconView.VisibleState
     public int getVisibleState() {
         return mVisibleState;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
index 25c6dce..48c6e27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarMobileView.java
@@ -59,7 +59,8 @@
     private ImageView mOut;
     private ImageView mMobile, mMobileType, mMobileRoaming;
     private View mMobileRoamingSpace;
-    private int mVisibleState = -1;
+    @StatusBarIconView.VisibleState
+    private int mVisibleState = STATE_HIDDEN;
     private DualToneHandler mDualToneHandler;
     private boolean mForceHidden;
 
@@ -271,7 +272,7 @@
     }
 
     @Override
-    public void setVisibleState(int state, boolean animate) {
+    public void setVisibleState(@StatusBarIconView.VisibleState int state, boolean animate) {
         if (state == mVisibleState) {
             return;
         }
@@ -312,6 +313,7 @@
     }
 
     @Override
+    @StatusBarIconView.VisibleState
     public int getVisibleState() {
         return mVisibleState;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
index 5aee62e..f3e74d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarWifiView.java
@@ -55,7 +55,8 @@
     private View mAirplaneSpacer;
     private WifiIconState mState;
     private String mSlot;
-    private int mVisibleState = -1;
+    @StatusBarIconView.VisibleState
+    private int mVisibleState = STATE_HIDDEN;
 
     public static StatusBarWifiView fromContext(Context context, String slot) {
         LayoutInflater inflater = LayoutInflater.from(context);
@@ -107,7 +108,7 @@
     }
 
     @Override
-    public void setVisibleState(int state, boolean animate) {
+    public void setVisibleState(@StatusBarIconView.VisibleState int state, boolean animate) {
         if (state == mVisibleState) {
             return;
         }
@@ -131,6 +132,7 @@
     }
 
     @Override
+    @StatusBarIconView.VisibleState
     public int getVisibleState() {
         return mVisibleState;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
index d541fae..1196211 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusIconDisplayable.java
@@ -22,14 +22,32 @@
     String getSlot();
     void setStaticDrawableColor(int color);
     void setDecorColor(int color);
-    default void setVisibleState(int state) {
+
+    /** Sets the visible state that this displayable should be. */
+    default void setVisibleState(@StatusBarIconView.VisibleState int state) {
         setVisibleState(state, false);
     }
-    void setVisibleState(int state, boolean animate);
+
+    /**
+     * Sets the visible state that this displayable should be, and whether the change should
+     * animate.
+     */
+    void setVisibleState(@StatusBarIconView.VisibleState int state, boolean animate);
+
+    /** Returns the current visible state of this displayable. */
+    @StatusBarIconView.VisibleState
     int getVisibleState();
+
+    /**
+     * Returns true if this icon should be visible if there's space, and false otherwise.
+     *
+     * Note that this doesn't necessarily mean it *will* be visible. It's possible that there are
+     * more icons than space, in which case this icon might just show a dot or might be completely
+     * hidden. {@link #getVisibleState} will return the icon's actual visible status.
+     */
     boolean isIconVisible();
+
     default boolean isIconBlocked() {
         return false;
     }
 }
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index ce2c9c2..0026b71 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -352,8 +352,8 @@
         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
         mDisableStateTracker.startTracking(mCommandQueue, mView.getDisplay().getDisplayId());
         if (mTintedIconManager == null) {
-            mTintedIconManager =
-                    mTintedIconManagerFactory.create(mView.findViewById(R.id.statusIcons));
+            mTintedIconManager = mTintedIconManagerFactory.create(
+                    mView.findViewById(R.id.statusIcons), StatusBarLocation.KEYGUARD);
             mTintedIconManager.setBlockList(getBlockedIcons());
             mStatusBarIconController.addIconGroup(mTintedIconManager);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index bd99713..d6d021f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -56,7 +56,6 @@
 import java.util.List;
 
 import javax.inject.Inject;
-import javax.inject.Provider;
 
 public interface StatusBarIconController {
 
@@ -139,13 +138,15 @@
 
         public DarkIconManager(
                 LinearLayout linearLayout,
+                StatusBarLocation location,
                 StatusBarPipelineFlags statusBarPipelineFlags,
-                Provider<WifiViewModel> wifiViewModelProvider,
+                WifiViewModel wifiViewModel,
                 MobileContextProvider mobileContextProvider,
                 DarkIconDispatcher darkIconDispatcher) {
             super(linearLayout,
+                    location,
                     statusBarPipelineFlags,
-                    wifiViewModelProvider,
+                    wifiViewModel,
                     mobileContextProvider);
             mIconHPadding = mContext.getResources().getDimensionPixelSize(
                     R.dimen.status_bar_icon_padding);
@@ -204,27 +205,28 @@
         @SysUISingleton
         public static class Factory {
             private final StatusBarPipelineFlags mStatusBarPipelineFlags;
-            private final Provider<WifiViewModel> mWifiViewModelProvider;
+            private final WifiViewModel mWifiViewModel;
             private final MobileContextProvider mMobileContextProvider;
             private final DarkIconDispatcher mDarkIconDispatcher;
 
             @Inject
             public Factory(
                     StatusBarPipelineFlags statusBarPipelineFlags,
-                    Provider<WifiViewModel> wifiViewModelProvider,
+                    WifiViewModel wifiViewModel,
                     MobileContextProvider mobileContextProvider,
                     DarkIconDispatcher darkIconDispatcher) {
                 mStatusBarPipelineFlags = statusBarPipelineFlags;
-                mWifiViewModelProvider = wifiViewModelProvider;
+                mWifiViewModel = wifiViewModel;
                 mMobileContextProvider = mobileContextProvider;
                 mDarkIconDispatcher = darkIconDispatcher;
             }
 
-            public DarkIconManager create(LinearLayout group) {
+            public DarkIconManager create(LinearLayout group, StatusBarLocation location) {
                 return new DarkIconManager(
                         group,
+                        location,
                         mStatusBarPipelineFlags,
-                        mWifiViewModelProvider,
+                        mWifiViewModel,
                         mMobileContextProvider,
                         mDarkIconDispatcher);
             }
@@ -239,12 +241,14 @@
 
         public TintedIconManager(
                 ViewGroup group,
+                StatusBarLocation location,
                 StatusBarPipelineFlags statusBarPipelineFlags,
-                Provider<WifiViewModel> wifiViewModelProvider,
+                WifiViewModel wifiViewModel,
                 MobileContextProvider mobileContextProvider) {
             super(group,
+                    location,
                     statusBarPipelineFlags,
-                    wifiViewModelProvider,
+                    wifiViewModel,
                     mobileContextProvider);
         }
 
@@ -278,24 +282,25 @@
         @SysUISingleton
         public static class Factory {
             private final StatusBarPipelineFlags mStatusBarPipelineFlags;
-            private final Provider<WifiViewModel> mWifiViewModelProvider;
+            private final WifiViewModel mWifiViewModel;
             private final MobileContextProvider mMobileContextProvider;
 
             @Inject
             public Factory(
                     StatusBarPipelineFlags statusBarPipelineFlags,
-                    Provider<WifiViewModel> wifiViewModelProvider,
+                    WifiViewModel wifiViewModel,
                     MobileContextProvider mobileContextProvider) {
                 mStatusBarPipelineFlags = statusBarPipelineFlags;
-                mWifiViewModelProvider = wifiViewModelProvider;
+                mWifiViewModel = wifiViewModel;
                 mMobileContextProvider = mobileContextProvider;
             }
 
-            public TintedIconManager create(ViewGroup group) {
+            public TintedIconManager create(ViewGroup group, StatusBarLocation location) {
                 return new TintedIconManager(
                         group,
+                        location,
                         mStatusBarPipelineFlags,
-                        mWifiViewModelProvider,
+                        mWifiViewModel,
                         mMobileContextProvider);
             }
         }
@@ -306,8 +311,9 @@
      */
     class IconManager implements DemoModeCommandReceiver {
         protected final ViewGroup mGroup;
+        private final StatusBarLocation mLocation;
         private final StatusBarPipelineFlags mStatusBarPipelineFlags;
-        private final Provider<WifiViewModel> mWifiViewModelProvider;
+        private final WifiViewModel mWifiViewModel;
         private final MobileContextProvider mMobileContextProvider;
         protected final Context mContext;
         protected final int mIconSize;
@@ -324,12 +330,14 @@
 
         public IconManager(
                 ViewGroup group,
+                StatusBarLocation location,
                 StatusBarPipelineFlags statusBarPipelineFlags,
-                Provider<WifiViewModel> wifiViewModelProvider,
+                WifiViewModel wifiViewModel,
                 MobileContextProvider mobileContextProvider) {
             mGroup = group;
+            mLocation = location;
             mStatusBarPipelineFlags = statusBarPipelineFlags;
-            mWifiViewModelProvider = wifiViewModelProvider;
+            mWifiViewModel = wifiViewModel;
             mMobileContextProvider = mobileContextProvider;
             mContext = group.getContext();
             mIconSize = mContext.getResources().getDimensionPixelSize(
@@ -446,7 +454,7 @@
 
         private ModernStatusBarWifiView onCreateModernStatusBarWifiView(String slot) {
             return ModernStatusBarWifiView.constructAndBind(
-                    mContext, slot, mWifiViewModelProvider.get());
+                    mContext, slot, mWifiViewModel, mLocation);
         }
 
         private StatusBarMobileView onCreateStatusBarMobileView(int subId, String slot) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index e61794b..9d5392a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -730,7 +730,9 @@
     private void setDozing(boolean dozing) {
         if (mDozing != dozing) {
             mDozing = dozing;
-            reset(true /* hideBouncerWhenShowing */);
+            if (dozing || mBouncer.needsFullscreenBouncer() || mOccluded) {
+                reset(dozing /* hideBouncerWhenShowing */);
+            }
             updateStates();
 
             if (!dozing) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
similarity index 64%
copy from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
copy to packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
index 44c0496..5ace226 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarLocation.kt
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.pipeline.wifi.data.model
+package com.android.systemui.statusbar.phone
 
-/**
- * Provides information on the current wifi activity.
- */
-data class WifiActivityModel(
-    /** True if the wifi has activity in (download). */
-    val hasActivityIn: Boolean,
-    /** True if the wifi has activity out (upload). */
-    val hasActivityOut: Boolean,
-)
+/** An enumeration of the different locations that host a status bar. */
+enum class StatusBarLocation {
+    /** Home screen or in-app. */
+    HOME,
+    /** Keyguard (aka lockscreen). */
+    KEYGUARD,
+    /** Quick settings (inside the shade). */
+    QS,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index ce04fb5..e1215ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -68,6 +68,7 @@
 import com.android.systemui.statusbar.phone.StatusBarHideIconsForBouncerManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
+import com.android.systemui.statusbar.phone.StatusBarLocation;
 import com.android.systemui.statusbar.phone.StatusBarLocationPublisher;
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent;
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent.Startable;
@@ -250,7 +251,8 @@
             mStatusBar.restoreHierarchyState(
                     savedInstanceState.getSparseParcelableArray(EXTRA_PANEL_STATE));
         }
-        mDarkIconManager = mDarkIconManagerFactory.create(view.findViewById(R.id.statusIcons));
+        mDarkIconManager = mDarkIconManagerFactory.create(
+                view.findViewById(R.id.statusIcons), StatusBarLocation.HOME);
         mDarkIconManager.setShouldLog(true);
         updateBlockedIcons();
         mStatusBarIconController.addIconGroup(mDarkIconManager);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt
new file mode 100644
index 0000000..118b94c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityConstants.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared
+
+import android.telephony.TelephonyManager
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/**
+ * An object storing constants that are used for calculating connectivity icons.
+ *
+ * Stored in a class for logging purposes.
+ */
+@SysUISingleton
+class ConnectivityConstants
+@Inject
+constructor(dumpManager: DumpManager, telephonyManager: TelephonyManager) : Dumpable {
+    init {
+        dumpManager.registerDumpable("$SB_LOGGING_TAG:ConnectivityConstants", this)
+    }
+
+    /** True if this device has the capability for data connections and false otherwise. */
+    val hasDataCapabilities = telephonyManager.isDataCapable
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.apply { println("hasDataCapabilities=$hasDataCapabilities") }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
index 88d8a86..dbb1aa5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLogger.kt
@@ -33,6 +33,20 @@
 ) {
     /**
      * Logs a change in one of the **raw inputs** to the connectivity pipeline.
+     *
+     * Use this method for inputs that don't have any extra information besides their callback name.
+     */
+    fun logInputChange(callbackName: String) {
+        buffer.log(
+            SB_LOGGING_TAG,
+            LogLevel.INFO,
+            { str1 = callbackName },
+            { "Input: $str1" }
+        )
+    }
+
+    /**
+     * Logs a change in one of the **raw inputs** to the connectivity pipeline.
      */
     fun logInputChange(callbackName: String, changeInfo: String?) {
         buffer.log(
@@ -128,12 +142,36 @@
         const val SB_LOGGING_TAG = "SbConnectivity"
 
         /**
+         * Log a change in one of the **inputs** to the connectivity pipeline.
+         */
+        fun Flow<Unit>.logInputChange(
+            logger: ConnectivityPipelineLogger,
+            inputParamName: String,
+        ): Flow<Unit> {
+            return this.onEach { logger.logInputChange(inputParamName) }
+        }
+
+        /**
+         * Log a change in one of the **inputs** to the connectivity pipeline.
+         *
+         * @param prettyPrint an optional function to transform the value into a readable string.
+         *   [toString] is used if no custom function is provided.
+         */
+        fun <T> Flow<T>.logInputChange(
+            logger: ConnectivityPipelineLogger,
+            inputParamName: String,
+            prettyPrint: (T) -> String = { it.toString() }
+        ): Flow<T> {
+            return this.onEach {logger.logInputChange(inputParamName, prettyPrint(it)) }
+        }
+
+        /**
          * Log a change in one of the **outputs** to the connectivity pipeline.
          *
          * @param prettyPrint an optional function to transform the value into a readable string.
          *   [toString] is used if no custom function is provided.
          */
-        fun <T : Any> Flow<T>.logOutputChange(
+        fun <T> Flow<T>.logOutputChange(
                 logger: ConnectivityPipelineLogger,
                 outputParamName: String,
                 prettyPrint: (T) -> String = { it.toString() }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
index 103f3fc..681cf72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.pipeline.wifi.data.repository
 
 import android.annotation.SuppressLint
+import android.content.IntentFilter
 import android.net.ConnectivityManager
 import android.net.Network
 import android.net.NetworkCapabilities
@@ -30,51 +31,87 @@
 import android.net.wifi.WifiManager.TrafficStateCallback
 import android.util.Log
 import com.android.settingslib.Utils
+import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
-import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import java.util.concurrent.Executor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.stateIn
 
-/**
- * Provides data related to the wifi state.
- */
+/** Provides data related to the wifi state. */
 interface WifiRepository {
-    /**
-     * Observable for the current wifi network.
-     */
-    val wifiNetwork: Flow<WifiNetworkModel>
+    /** Observable for the current wifi enabled status. */
+    val isWifiEnabled: StateFlow<Boolean>
 
-    /**
-     * Observable for the current wifi network activity.
-     */
-    val wifiActivity: Flow<WifiActivityModel>
+    /** Observable for the current wifi network. */
+    val wifiNetwork: StateFlow<WifiNetworkModel>
+
+    /** Observable for the current wifi network activity. */
+    val wifiActivity: StateFlow<WifiActivityModel>
 }
 
 /** Real implementation of [WifiRepository]. */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @OptIn(ExperimentalCoroutinesApi::class)
 @SysUISingleton
 @SuppressLint("MissingPermission")
 class WifiRepositoryImpl @Inject constructor(
+    broadcastDispatcher: BroadcastDispatcher,
     connectivityManager: ConnectivityManager,
     logger: ConnectivityPipelineLogger,
     @Main mainExecutor: Executor,
     @Application scope: CoroutineScope,
     wifiManager: WifiManager?,
 ) : WifiRepository {
-    override val wifiNetwork: Flow<WifiNetworkModel> = conflatedCallbackFlow {
+
+    private val wifiStateChangeEvents: Flow<Unit> = broadcastDispatcher.broadcastFlow(
+        IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION)
+    )
+        .logInputChange(logger, "WIFI_STATE_CHANGED_ACTION intent")
+
+    private val wifiNetworkChangeEvents: MutableSharedFlow<Unit> =
+        MutableSharedFlow(extraBufferCapacity = 1)
+
+    override val isWifiEnabled: StateFlow<Boolean> =
+        if (wifiManager == null) {
+            MutableStateFlow(false).asStateFlow()
+        } else {
+            // Because [WifiManager] doesn't expose a wifi enabled change listener, we do it
+            // internally by fetching [WifiManager.isWifiEnabled] whenever we think the state may
+            // have changed.
+            merge(wifiNetworkChangeEvents, wifiStateChangeEvents)
+                .mapLatest { wifiManager.isWifiEnabled }
+                .distinctUntilChanged()
+                .logOutputChange(logger, "enabled")
+                .stateIn(
+                    scope = scope,
+                    started = SharingStarted.WhileSubscribed(),
+                    initialValue = wifiManager.isWifiEnabled
+                )
+        }
+
+    override val wifiNetwork: StateFlow<WifiNetworkModel> = conflatedCallbackFlow {
         var currentWifi: WifiNetworkModel = WIFI_NETWORK_DEFAULT
 
         val callback = object : ConnectivityManager.NetworkCallback(FLAG_INCLUDE_LOCATION_INFO) {
@@ -84,6 +121,8 @@
             ) {
                 logger.logOnCapabilitiesChanged(network, networkCapabilities)
 
+                wifiNetworkChangeEvents.tryEmit(Unit)
+
                 val wifiInfo = networkCapabilitiesToWifiInfo(networkCapabilities)
                 if (wifiInfo?.isPrimary == true) {
                     val wifiNetworkModel = createWifiNetworkModel(
@@ -104,6 +143,9 @@
 
             override fun onLost(network: Network) {
                 logger.logOnLost(network)
+
+                wifiNetworkChangeEvents.tryEmit(Unit)
+
                 val wifi = currentWifi
                 if (wifi is WifiNetworkModel.Active && wifi.networkId == network.getNetId()) {
                     val newNetworkModel = WifiNetworkModel.Inactive
@@ -132,7 +174,7 @@
             initialValue = WIFI_NETWORK_DEFAULT
         )
 
-    override val wifiActivity: Flow<WifiActivityModel> =
+    override val wifiActivity: StateFlow<WifiActivityModel> =
             if (wifiManager == null) {
                 Log.w(SB_LOGGING_TAG, "Null WifiManager; skipping activity callback")
                 flowOf(ACTIVITY_DEFAULT)
@@ -142,13 +184,15 @@
                         logger.logInputChange("onTrafficStateChange", prettyPrintActivity(state))
                         trySend(trafficStateToWifiActivityModel(state))
                     }
-
-                    trySend(ACTIVITY_DEFAULT)
                     wifiManager.registerTrafficStateCallback(mainExecutor, callback)
-
                     awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
                 }
             }
+                .stateIn(
+                    scope,
+                    started = SharingStarted.WhileSubscribed(),
+                    initialValue = ACTIVITY_DEFAULT
+                )
 
     companion object {
         val ACTIVITY_DEFAULT = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
index 952525d..04b17ed 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
@@ -22,9 +22,10 @@
 import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.map
 
 /**
@@ -38,7 +39,11 @@
     connectivityRepository: ConnectivityRepository,
     wifiRepository: WifiRepository,
 ) {
-    private val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
+    /**
+     * The SSID (service set identifier) of the wifi network. Null if we don't have a network, or
+     * have a network but no valid SSID.
+     */
+    val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
         when (info) {
             is WifiNetworkModel.Inactive -> null
             is WifiNetworkModel.CarrierMerged -> null
@@ -51,17 +56,17 @@
         }
     }
 
+    /** Our current enabled status. */
+    val isEnabled: Flow<Boolean> = wifiRepository.isWifiEnabled
+
     /** Our current wifi network. See [WifiNetworkModel]. */
     val wifiNetwork: Flow<WifiNetworkModel> = wifiRepository.wifiNetwork
 
+    /** Our current wifi activity. See [WifiActivityModel]. */
+    val activity: StateFlow<WifiActivityModel> = wifiRepository.wifiActivity
+
     /** True if we're configured to force-hide the wifi icon and false otherwise. */
     val isForceHidden: Flow<Boolean> = connectivityRepository.forceHiddenSlots.map {
         it.contains(ConnectivitySlot.WIFI)
     }
-
-    /** True if our wifi network has activity in (download), and false otherwise. */
-    val hasActivityIn: Flow<Boolean> =
-        combine(wifiRepository.wifiActivity, ssid) { activity, ssid ->
-            activity.hasActivityIn && ssid != null
-        }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
index a19d1bd..0eb4b0d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/WifiConstants.kt
@@ -41,9 +41,14 @@
     /** True if we should show the activityIn/activityOut icons and false otherwise. */
     val shouldShowActivityConfig = context.resources.getBoolean(R.bool.config_showActivity)
 
+    /** True if we should always show the wifi icon when wifi is enabled and false otherwise. */
+    val alwaysShowIconIfEnabled =
+        context.resources.getBoolean(R.bool.config_showWifiIndicatorWhenEnabled)
+
     override fun dump(pw: PrintWriter, args: Array<out String>) {
         pw.apply {
             println("shouldShowActivityConfig=$shouldShowActivityConfig")
+            println("alwaysShowIconIfEnabled=$alwaysShowIconIfEnabled")
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiActivityModel.kt
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiActivityModel.kt
index 44c0496..5746106 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiActivityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiActivityModel.kt
@@ -14,11 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.statusbar.pipeline.wifi.data.model
+package com.android.systemui.statusbar.pipeline.wifi.shared.model
 
-/**
- * Provides information on the current wifi activity.
- */
+/** Provides information on the current wifi activity. */
 data class WifiActivityModel(
     /** True if the wifi has activity in (download). */
     val hasActivityIn: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
index 4fad327..273be63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/binder/WifiViewBinder.kt
@@ -26,8 +26,15 @@
 import com.android.systemui.R
 import com.android.systemui.common.ui.binder.IconViewBinder
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
+import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
+import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
+import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel
 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
 import kotlinx.coroutines.InternalCoroutinesApi
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.launch
@@ -41,40 +48,111 @@
  */
 @OptIn(InternalCoroutinesApi::class)
 object WifiViewBinder {
-    /** Binds the view to the view-model, continuing to update the former based on the latter. */
+
+    /**
+     * Defines interface for an object that acts as the binding between the view and its view-model.
+     *
+     * Users of the [WifiViewBinder] class should use this to control the binder after it is bound.
+     */
+    interface Binding {
+        /** Returns true if the wifi icon should be visible and false otherwise. */
+        fun getShouldIconBeVisible(): Boolean
+
+        /** Notifies that the visibility state has changed. */
+        fun onVisibilityStateChanged(@StatusBarIconView.VisibleState state: Int)
+    }
+
+    /**
+     * Binds the view to the appropriate view-model based on the given location. The view will
+     * continue to be updated following updates from the view-model.
+     */
     @JvmStatic
     fun bind(
         view: ViewGroup,
-        viewModel: WifiViewModel,
-    ) {
+        wifiViewModel: WifiViewModel,
+        location: StatusBarLocation,
+    ): Binding {
+        return when (location) {
+            StatusBarLocation.HOME -> bind(view, wifiViewModel.home)
+            StatusBarLocation.KEYGUARD -> bind(view, wifiViewModel.keyguard)
+            StatusBarLocation.QS -> bind(view, wifiViewModel.qs)
+        }
+    }
+
+    /** Binds the view to the view-model, continuing to update the former based on the latter. */
+    @JvmStatic
+    private fun bind(
+        view: ViewGroup,
+        viewModel: LocationBasedWifiViewModel,
+    ): Binding {
+        val groupView = view.requireViewById<ViewGroup>(R.id.wifi_group)
         val iconView = view.requireViewById<ImageView>(R.id.wifi_signal)
+        val dotView = view.requireViewById<StatusBarIconView>(R.id.status_bar_dot)
+        val activityInView = view.requireViewById<ImageView>(R.id.wifi_in)
+        val activityOutView = view.requireViewById<ImageView>(R.id.wifi_out)
+        val activityContainerView = view.requireViewById<View>(R.id.inout_container)
 
         view.isVisible = true
         iconView.isVisible = true
 
+        // TODO(b/238425913): We should log this visibility state.
+        @StatusBarIconView.VisibleState
+        val visibilityState: MutableStateFlow<Int> = MutableStateFlow(STATE_HIDDEN)
+
         view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
                 launch {
-                    viewModel.wifiIcon.distinctUntilChanged().collect { wifiIcon ->
-                        // TODO(b/238425913): Right now, if !isVisible, there's just an empty space
-                        //  where the wifi icon would be. We need to pipe isVisible through to
-                        //   [ModernStatusBarWifiView.isIconVisible], which is what actually makes
-                        //   the view GONE.
+                    visibilityState.collect { visibilityState ->
+                        groupView.isVisible = visibilityState == STATE_ICON
+                        dotView.isVisible = visibilityState == STATE_DOT
+                    }
+                }
+
+                launch {
+                    viewModel.wifiIcon.collect { wifiIcon ->
                         view.isVisible = wifiIcon != null
-                        wifiIcon?.let {
-                            IconViewBinder.bind(wifiIcon, iconView)
-                        }
+                        wifiIcon?.let { IconViewBinder.bind(wifiIcon, iconView) }
                     }
                 }
 
                 launch {
                     viewModel.tint.collect { tint ->
-                        iconView.imageTintList = ColorStateList.valueOf(tint)
+                        val tintList = ColorStateList.valueOf(tint)
+                        iconView.imageTintList = tintList
+                        activityInView.imageTintList = tintList
+                        activityOutView.imageTintList = tintList
+                        dotView.setDecorColor(tint)
+                    }
+                }
+
+                launch {
+                    viewModel.isActivityInViewVisible.distinctUntilChanged().collect { visible ->
+                        activityInView.isVisible = visible
+                    }
+                }
+
+                launch {
+                    viewModel.isActivityOutViewVisible.distinctUntilChanged().collect { visible ->
+                        activityOutView.isVisible = visible
+                    }
+                }
+
+                launch {
+                    viewModel.isActivityContainerVisible.distinctUntilChanged().collect { visible ->
+                        activityContainerView.isVisible = visible
                     }
                 }
             }
         }
 
-        // TODO(b/238425913): Hook up to [viewModel] to render actual changes to the wifi icon.
+        return object : Binding {
+            override fun getShouldIconBeVisible(): Boolean {
+                return viewModel.wifiIcon.value != null
+            }
+
+            override fun onVisibilityStateChanged(@StatusBarIconView.VisibleState state: Int) {
+                visibilityState.value = state
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
index c14a897..6c616ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiView.kt
@@ -19,10 +19,14 @@
 import android.content.Context
 import android.graphics.Rect
 import android.util.AttributeSet
+import android.view.Gravity
 import android.view.LayoutInflater
 import com.android.systemui.R
 import com.android.systemui.statusbar.BaseStatusBarWifiView
-import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
+import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
+import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
+import com.android.systemui.statusbar.phone.StatusBarLocation
 import com.android.systemui.statusbar.pipeline.wifi.ui.binder.WifiViewBinder
 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
 
@@ -36,6 +40,17 @@
 ) : BaseStatusBarWifiView(context, attrs) {
 
     private lateinit var slot: String
+    private lateinit var binding: WifiViewBinder.Binding
+
+    @StatusBarIconView.VisibleState
+    private var iconVisibleState: Int = STATE_HIDDEN
+        set(value) {
+            if (field == value) {
+                return
+            }
+            field = value
+            binding.onVisibilityStateChanged(value)
+        }
 
     override fun onDarkChanged(areas: ArrayList<Rect>?, darkIntensity: Float, tint: Int) {
         // TODO(b/238425913)
@@ -51,42 +66,64 @@
         // TODO(b/238425913)
     }
 
-    override fun setVisibleState(state: Int, animate: Boolean) {
-        // TODO(b/238425913)
+    override fun setVisibleState(@StatusBarIconView.VisibleState state: Int, animate: Boolean) {
+        iconVisibleState = state
     }
 
+    @StatusBarIconView.VisibleState
     override fun getVisibleState(): Int {
-        // TODO(b/238425913)
-        return STATE_ICON
+        return iconVisibleState
     }
 
     override fun isIconVisible(): Boolean {
-        // TODO(b/238425913)
-        return true
+        return binding.getShouldIconBeVisible()
     }
 
-    /** Set the slot name for this view. */
-    private fun setSlot(slotName: String) {
-        this.slot = slotName
+    private fun initView(
+        slotName: String,
+        wifiViewModel: WifiViewModel,
+        location: StatusBarLocation,
+    ) {
+        slot = slotName
+        initDotView()
+        binding = WifiViewBinder.bind(this, wifiViewModel, location)
+    }
+
+    // Mostly duplicated from [com.android.systemui.statusbar.StatusBarWifiView].
+    private fun initDotView() {
+        // TODO(b/238425913): Could we just have this dot view be part of
+        //   R.layout.new_status_bar_wifi_group with a dot drawable so we don't need to inflate it
+        //   manually? Would that not work with animations?
+        val dotView = StatusBarIconView(mContext, slot, null).also {
+            it.id = R.id.status_bar_dot
+            // Hard-code this view to always be in the DOT state so that whenever it's visible it
+            // will show a dot
+            it.visibleState = STATE_DOT
+        }
+
+        val width = mContext.resources.getDimensionPixelSize(R.dimen.status_bar_icon_size)
+        val lp = LayoutParams(width, width)
+        lp.gravity = Gravity.CENTER_VERTICAL or Gravity.START
+        addView(dotView, lp)
     }
 
     companion object {
         /**
-         * Inflates a new instance of [ModernStatusBarWifiView], binds it to [viewModel], and
+         * Inflates a new instance of [ModernStatusBarWifiView], binds it to a view model, and
          * returns it.
          */
         @JvmStatic
         fun constructAndBind(
             context: Context,
             slot: String,
-            viewModel: WifiViewModel,
+            wifiViewModel: WifiViewModel,
+            location: StatusBarLocation,
         ): ModernStatusBarWifiView {
             return (
                 LayoutInflater.from(context).inflate(R.layout.new_status_bar_wifi_group, null)
                     as ModernStatusBarWifiView
                 ).also {
-                    it.setSlot(slot)
-                    WifiViewBinder.bind(it, viewModel)
+                    it.initView(slot, wifiViewModel, location)
                 }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/HomeWifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/HomeWifiViewModel.kt
new file mode 100644
index 0000000..40f948f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/HomeWifiViewModel.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.statusbar.pipeline.wifi.ui.viewmodel
+
+import android.graphics.Color
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+
+/**
+ * A view model for the wifi icon shown on the "home" page (aka, when the device is unlocked and not
+ * showing the shade, so the user is on the home-screen, or in an app).
+ */
+class HomeWifiViewModel(
+    statusBarPipelineFlags: StatusBarPipelineFlags,
+    wifiIcon: StateFlow<Icon.Resource?>,
+    isActivityInViewVisible: Flow<Boolean>,
+    isActivityOutViewVisible: Flow<Boolean>,
+    isActivityContainerVisible: Flow<Boolean>,
+) :
+    LocationBasedWifiViewModel(
+        statusBarPipelineFlags,
+        debugTint = Color.CYAN,
+        wifiIcon,
+        isActivityInViewVisible,
+        isActivityOutViewVisible,
+        isActivityContainerVisible,
+    )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/KeyguardWifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/KeyguardWifiViewModel.kt
new file mode 100644
index 0000000..9642ac4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/KeyguardWifiViewModel.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.statusbar.pipeline.wifi.ui.viewmodel
+
+import android.graphics.Color
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+
+/** A view model for the wifi icon shown on keyguard (lockscreen). */
+class KeyguardWifiViewModel(
+    statusBarPipelineFlags: StatusBarPipelineFlags,
+    wifiIcon: StateFlow<Icon.Resource?>,
+    isActivityInViewVisible: Flow<Boolean>,
+    isActivityOutViewVisible: Flow<Boolean>,
+    isActivityContainerVisible: Flow<Boolean>,
+) :
+    LocationBasedWifiViewModel(
+        statusBarPipelineFlags,
+        debugTint = Color.MAGENTA,
+        wifiIcon,
+        isActivityInViewVisible,
+        isActivityOutViewVisible,
+        isActivityContainerVisible,
+    )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt
new file mode 100644
index 0000000..e23f8c7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/LocationBasedWifiViewModel.kt
@@ -0,0 +1,68 @@
+/*
+ * 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.statusbar.pipeline.wifi.ui.viewmodel
+
+import android.graphics.Color
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.flowOf
+
+/**
+ * A view model for a wifi icon in a specific location. This allows us to control parameters that
+ * are location-specific (for example, different tints of the icon in different locations).
+ *
+ * Must be subclassed for each distinct location.
+ */
+abstract class LocationBasedWifiViewModel(
+    statusBarPipelineFlags: StatusBarPipelineFlags,
+    debugTint: Int,
+
+    /** The wifi icon that should be displayed. Null if we shouldn't display any icon. */
+    val wifiIcon: StateFlow<Icon.Resource?>,
+
+    /** True if the activity in view should be visible. */
+    val isActivityInViewVisible: Flow<Boolean>,
+
+    /** True if the activity out view should be visible. */
+    val isActivityOutViewVisible: Flow<Boolean>,
+
+    /** True if the activity container view should be visible. */
+    val isActivityContainerVisible: Flow<Boolean>,
+) {
+    /** The color that should be used to tint the icon. */
+    val tint: Flow<Int> =
+        flowOf(
+            if (statusBarPipelineFlags.useNewPipelineDebugColoring()) {
+                debugTint
+            } else {
+                DEFAULT_TINT
+            }
+        )
+
+    companion object {
+        /**
+         * A default icon tint.
+         *
+         * TODO(b/238425913): The tint is actually controlled by
+         * [com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager]. We
+         * should use that logic instead of white as a default.
+         */
+        private const val DEFAULT_TINT = Color.WHITE
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/QsWifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/QsWifiViewModel.kt
new file mode 100644
index 0000000..0ddf90e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/QsWifiViewModel.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.statusbar.pipeline.wifi.ui.viewmodel
+
+import android.graphics.Color
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.StateFlow
+
+/** A view model for the wifi icon shown in quick settings (when the shade is pulled down). */
+class QsWifiViewModel(
+    statusBarPipelineFlags: StatusBarPipelineFlags,
+    wifiIcon: StateFlow<Icon.Resource?>,
+    isActivityInViewVisible: Flow<Boolean>,
+    isActivityOutViewVisible: Flow<Boolean>,
+    isActivityContainerVisible: Flow<Boolean>,
+) :
+    LocationBasedWifiViewModel(
+        statusBarPipelineFlags,
+        debugTint = Color.GREEN,
+        wifiIcon,
+        isActivityInViewVisible,
+        isActivityOutViewVisible,
+        isActivityContainerVisible,
+    )
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
index 3c243ac..ebbd77b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
 
 import android.content.Context
-import android.graphics.Color
 import androidx.annotation.DrawableRes
 import androidx.annotation.StringRes
 import androidx.annotation.VisibleForTesting
@@ -26,107 +25,185 @@
 import com.android.systemui.R
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK
 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
 
 /**
  * Models the UI state for the status bar wifi icon.
+ *
+ * This class exposes three view models, one per status bar location:
+ *  - [home]
+ *  - [keyguard]
+ *  - [qs]
+ *  In order to get the UI state for the wifi icon, you must use one of those view models (whichever
+ *  is correct for your location).
+ *
+ * Internally, this class maintains the current state of the wifi icon and notifies those three
+ * view models of any changes.
  */
-class WifiViewModel @Inject constructor(
-    statusBarPipelineFlags: StatusBarPipelineFlags,
-    private val constants: WifiConstants,
+@SysUISingleton
+class WifiViewModel
+@Inject
+constructor(
+    connectivityConstants: ConnectivityConstants,
     private val context: Context,
-    private val logger: ConnectivityPipelineLogger,
-    private val interactor: WifiInteractor,
+    logger: ConnectivityPipelineLogger,
+    interactor: WifiInteractor,
+    @Application private val scope: CoroutineScope,
+    statusBarPipelineFlags: StatusBarPipelineFlags,
+    wifiConstants: WifiConstants,
 ) {
     /**
-     * The drawable resource ID to use for the wifi icon. Null if we shouldn't display any icon.
+     * Returns the drawable resource ID to use for the wifi icon based on the given network.
+     * Null if we can't compute the icon.
      */
     @DrawableRes
-    private val iconResId: Flow<Int?> = interactor.wifiNetwork.map {
-        when (it) {
+    private fun WifiNetworkModel.iconResId(): Int? {
+        return when (this) {
             is WifiNetworkModel.CarrierMerged -> null
             is WifiNetworkModel.Inactive -> WIFI_NO_NETWORK
             is WifiNetworkModel.Active ->
                 when {
-                    it.level == null -> null
-                    it.isValidated -> WIFI_FULL_ICONS[it.level]
-                    else -> WIFI_NO_INTERNET_ICONS[it.level]
+                    this.level == null -> null
+                    this.isValidated -> WIFI_FULL_ICONS[this.level]
+                    else -> WIFI_NO_INTERNET_ICONS[this.level]
                 }
         }
     }
 
-    /** The content description for the wifi icon. */
-    private val contentDescription: Flow<ContentDescription?> = interactor.wifiNetwork.map {
-        when (it) {
+    /**
+     * Returns the content description for the wifi icon based on the given network.
+     * Null if we can't compute the content description.
+     */
+    private fun WifiNetworkModel.contentDescription(): ContentDescription? {
+        return when (this) {
             is WifiNetworkModel.CarrierMerged -> null
             is WifiNetworkModel.Inactive ->
                 ContentDescription.Loaded(
                     "${context.getString(WIFI_NO_CONNECTION)},${context.getString(NO_INTERNET)}"
                 )
             is WifiNetworkModel.Active ->
-                when (it.level) {
+                when (this.level) {
                     null -> null
                     else -> {
-                        val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[it.level])
+                        val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[this.level])
                         when {
-                            it.isValidated -> ContentDescription.Loaded(levelDesc)
-                            else -> ContentDescription.Loaded(
-                                "$levelDesc,${context.getString(NO_INTERNET)}"
-                            )
+                            this.isValidated -> ContentDescription.Loaded(levelDesc)
+                            else ->
+                                ContentDescription.Loaded(
+                                    "$levelDesc,${context.getString(NO_INTERNET)}"
+                                )
                         }
                     }
                 }
         }
     }
 
-    /**
-     * The wifi icon that should be displayed. Null if we shouldn't display any icon.
-     */
-    val wifiIcon: Flow<Icon?> = combine(
+    /** The wifi icon that should be displayed. Null if we shouldn't display any icon. */
+    private val wifiIcon: StateFlow<Icon.Resource?> =
+        combine(
+            interactor.isEnabled,
             interactor.isForceHidden,
-            iconResId,
-            contentDescription,
-        ) { isForceHidden, iconResId, contentDescription ->
-            when {
-                isForceHidden ||
-                    iconResId == null ||
-                    iconResId <= 0 -> null
-                else -> Icon.Resource(iconResId, contentDescription)
+            interactor.wifiNetwork,
+        ) { isEnabled, isForceHidden, wifiNetwork ->
+            if (!isEnabled || isForceHidden || wifiNetwork is WifiNetworkModel.CarrierMerged) {
+                return@combine null
+            }
+
+            val iconResId = wifiNetwork.iconResId() ?: return@combine null
+            val icon = Icon.Resource(iconResId, wifiNetwork.contentDescription())
+
+            return@combine when {
+                wifiConstants.alwaysShowIconIfEnabled -> icon
+                !connectivityConstants.hasDataCapabilities -> icon
+                wifiNetwork is WifiNetworkModel.Active && wifiNetwork.isValidated -> icon
+                else -> null
             }
         }
+        .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null)
 
-    /**
-     * True if the activity in icon should be displayed and false otherwise.
-     */
-    val isActivityInVisible: Flow<Boolean>
-        get() =
-            if (!constants.shouldShowActivityConfig) {
-                flowOf(false)
-            } else {
-                interactor.hasActivityIn
+    /** The wifi activity status. Null if we shouldn't display the activity status. */
+    private val activity: Flow<WifiActivityModel?> =
+        if (!wifiConstants.shouldShowActivityConfig) {
+            flowOf(null)
+        } else {
+            combine(interactor.activity, interactor.ssid) { activity, ssid ->
+                when (ssid) {
+                    null -> null
+                    else -> activity
+                }
             }
-                .logOutputChange(logger, "activityInVisible")
+        }
+        .distinctUntilChanged()
+        .logOutputChange(logger, "activity")
+        .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = null)
 
-    /** The tint that should be applied to the icon. */
-    val tint: Flow<Int> = if (!statusBarPipelineFlags.useNewPipelineDebugColoring()) {
-        emptyFlow()
-    } else {
-        flowOf(Color.CYAN)
-    }
+    private val isActivityInViewVisible: Flow<Boolean> =
+         activity
+             .map { it?.hasActivityIn == true }
+             .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
+
+    private val isActivityOutViewVisible: Flow<Boolean> =
+       activity
+           .map { it?.hasActivityOut == true }
+           .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
+
+    private val isActivityContainerVisible: Flow<Boolean> =
+         combine(isActivityInViewVisible, isActivityOutViewVisible) { activityIn, activityOut ->
+                    activityIn || activityOut
+                }
+             .stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
+
+    /** A view model for the status bar on the home screen. */
+    val home: HomeWifiViewModel =
+        HomeWifiViewModel(
+            statusBarPipelineFlags,
+            wifiIcon,
+            isActivityInViewVisible,
+            isActivityOutViewVisible,
+            isActivityContainerVisible,
+        )
+
+    /** A view model for the status bar on keyguard. */
+    val keyguard: KeyguardWifiViewModel =
+        KeyguardWifiViewModel(
+            statusBarPipelineFlags,
+            wifiIcon,
+            isActivityInViewVisible,
+            isActivityOutViewVisible,
+            isActivityContainerVisible,
+        )
+
+    /** A view model for the status bar in quick settings. */
+    val qs: QsWifiViewModel =
+        QsWifiViewModel(
+            statusBarPipelineFlags,
+            wifiIcon,
+            isActivityInViewVisible,
+            isActivityOutViewVisible,
+            isActivityContainerVisible,
+        )
 
     companion object {
         @StringRes
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 5a26d05..df10dfe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -1005,13 +1005,18 @@
         assertEquals(new Size(3, 3), resDelegate.getTopRoundedSize());
         assertEquals(new Size(4, 4), resDelegate.getBottomRoundedSize());
 
-        doReturn(2f).when(mScreenDecorations).getPhysicalPixelDisplaySizeRatio();
+        setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                getTestsDrawable(com.android.systemui.tests.R.drawable.rounded4px)
+                /* roundedTopDrawable */,
+                getTestsDrawable(com.android.systemui.tests.R.drawable.rounded5px)
+                /* roundedBottomDrawable */,
+                0 /* roundedPadding */, true /* privacyDot */, false /* faceScanning*/);
         mDisplayInfo.rotation = Surface.ROTATION_270;
 
         mScreenDecorations.onConfigurationChanged(null);
 
-        assertEquals(new Size(6, 6), resDelegate.getTopRoundedSize());
-        assertEquals(new Size(8, 8), resDelegate.getBottomRoundedSize());
+        assertEquals(new Size(4, 4), resDelegate.getTopRoundedSize());
+        assertEquals(new Size(5, 5), resDelegate.getBottomRoundedSize());
     }
 
     @Test
@@ -1288,6 +1293,51 @@
     }
 
     @Test
+    public void testOnDisplayChanged_hwcLayer() {
+        setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+        final DisplayDecorationSupport decorationSupport = new DisplayDecorationSupport();
+        decorationSupport.format = PixelFormat.R_8;
+        doReturn(decorationSupport).when(mDisplay).getDisplayDecorationSupport();
+
+        // top cutout
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+
+        mScreenDecorations.start();
+
+        final ScreenDecorHwcLayer hwcLayer = mScreenDecorations.mScreenDecorHwcLayer;
+        spyOn(hwcLayer);
+        doReturn(mDisplay).when(hwcLayer).getDisplay();
+
+        mScreenDecorations.mDisplayListener.onDisplayChanged(1);
+
+        verify(hwcLayer, times(1)).onDisplayChanged(any());
+    }
+
+    @Test
+    public void testOnDisplayChanged_nonHwcLayer() {
+        setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+                null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
+                0 /* roundedPadding */, false /* privacyDot */, false /* faceScanning */);
+
+        // top cutout
+        mMockCutoutList.add(new CutoutDecorProviderImpl(BOUNDS_POSITION_TOP));
+
+        mScreenDecorations.start();
+
+        final ScreenDecorations.DisplayCutoutView cutoutView = (ScreenDecorations.DisplayCutoutView)
+                mScreenDecorations.getOverlayView(R.id.display_cutout);
+        assertNotNull(cutoutView);
+        spyOn(cutoutView);
+        doReturn(mDisplay).when(cutoutView).getDisplay();
+
+        mScreenDecorations.mDisplayListener.onDisplayChanged(1);
+
+        verify(cutoutView, times(1)).onDisplayChanged(any());
+    }
+
+    @Test
     public void testHasSameProvidersWithNullOverlays() {
         setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
                 null /* roundedTopDrawable */, null /* roundedBottomDrawable */,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
index 08fe7c4..2a4c0eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
@@ -16,13 +16,14 @@
 
 package com.android.systemui.clipboardoverlay;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.content.ClipData;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.net.Uri;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import android.text.SpannableString;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -129,6 +130,18 @@
         assertEquals("image/png", target.getType());
     }
 
+    @Test
+    public void test_getShareIntent_spannableText() {
+        ClipData clipData = ClipData.newPlainText("Test", new SpannableString("Test Item"));
+        Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+
+        assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS);
+        Intent target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent.class);
+        assertEquals("Test Item", target.getStringExtra(Intent.EXTRA_TEXT));
+        assertEquals("text/plain", target.getType());
+    }
+
     // Assert that the given flags are set
     private void assertFlags(Intent intent, int flags) {
         assertTrue((intent.getFlags() & flags) == flags);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
index 93a1868b..f933361 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/decor/RoundedCornerResDelegateTest.kt
@@ -24,11 +24,12 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.R as InternalR
 import com.android.systemui.R as SystemUIR
-import com.android.systemui.SysuiTestCase
 import com.android.systemui.tests.R
+import com.android.systemui.SysuiTestCase
 import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
+
 import org.junit.runner.RunWith
 import org.mockito.Mock
 import org.mockito.MockitoAnnotations
@@ -101,11 +102,14 @@
         assertEquals(Size(3, 3), roundedCornerResDelegate.topRoundedSize)
         assertEquals(Size(4, 4), roundedCornerResDelegate.bottomRoundedSize)
 
-        roundedCornerResDelegate.physicalPixelDisplaySizeRatio = 2f
+        setupResources(radius = 100,
+                roundedTopDrawable = getTestsDrawable(R.drawable.rounded4px),
+                roundedBottomDrawable = getTestsDrawable(R.drawable.rounded5px))
+
         roundedCornerResDelegate.updateDisplayUniqueId(null, 1)
 
-        assertEquals(Size(6, 6), roundedCornerResDelegate.topRoundedSize)
-        assertEquals(Size(8, 8), roundedCornerResDelegate.bottomRoundedSize)
+        assertEquals(Size(4, 4), roundedCornerResDelegate.topRoundedSize)
+        assertEquals(Size(5, 5), roundedCornerResDelegate.bottomRoundedSize)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
index b42b769..8b1554c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogLiteTest.java
@@ -48,6 +48,7 @@
 import android.window.OnBackInvokedCallback;
 import android.window.OnBackInvokedDispatcher;
 
+import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.colorextraction.ColorExtractor;
@@ -234,6 +235,11 @@
         verify(mOnBackInvokedDispatcher).unregisterOnBackInvokedCallback(any());
     }
 
+    /**
+     * This specific test case appears to be flaky.
+     * b/249136797 tracks the task of root-causing and fixing it.
+     */
+    @FlakyTest
     @Test
     public void testPredictiveBackInvocationDismissesDialog() {
         mGlobalActionsDialogLite = spy(mGlobalActionsDialogLite);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index e3e3b74..5ad3542 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -30,7 +30,6 @@
 import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener
 import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
 import com.android.systemui.statusbar.policy.ConfigurationController
-import com.android.systemui.util.animation.TransitionLayout
 import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
@@ -46,7 +45,6 @@
 import org.mockito.Mock
 import org.mockito.Mockito.mock
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
@@ -73,10 +71,6 @@
     @Mock lateinit var dumpManager: DumpManager
     @Mock lateinit var logger: MediaUiEventLogger
     @Mock lateinit var debugLogger: MediaCarouselControllerLogger
-    @Mock lateinit var mediaViewHolder: MediaViewHolder
-    @Mock lateinit var player: TransitionLayout
-    @Mock lateinit var recommendationViewHolder: RecommendationViewHolder
-    @Mock lateinit var recommendations: TransitionLayout
     @Mock lateinit var mediaPlayer: MediaControlPanel
     @Mock lateinit var mediaViewController: MediaViewController
     @Mock lateinit var smartspaceMediaData: SmartspaceMediaData
@@ -282,46 +276,6 @@
         verify(logger).logRecommendationRemoved(eq(packageName), eq(instanceId!!))
     }
 
-    @Test
-    fun testSetSquishinessFractionForMedia_setPlayerBottom() {
-        whenever(panel.mediaViewHolder).thenReturn(mediaViewHolder)
-        whenever(mediaViewHolder.player).thenReturn(player)
-        whenever(player.measuredHeight).thenReturn(100)
-
-        val playingLocal = Triple("playing local",
-                DATA.copy(active = true, isPlaying = true,
-                        playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false),
-                4500L)
-        MediaPlayerData.addMediaPlayer(playingLocal.first, playingLocal.second, panel, clock,
-                false, debugLogger)
-
-        mediaCarouselController.squishinessFraction = 0.0f
-        verify(player).bottom = 50
-        verifyNoMoreInteractions(recommendationViewHolder)
-
-        mediaCarouselController.squishinessFraction = 0.5f
-        verify(player).bottom = 75
-        verifyNoMoreInteractions(recommendationViewHolder)
-    }
-
-    @Test
-    fun testSetSquishinessFractionForRecommendation_setPlayerBottom() {
-        whenever(panel.recommendationViewHolder).thenReturn(recommendationViewHolder)
-        whenever(recommendationViewHolder.recommendations).thenReturn(recommendations)
-        whenever(recommendations.measuredHeight).thenReturn(100)
-
-        MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, EMPTY_SMARTSPACE_MEDIA_DATA, panel,
-                false, clock)
-
-        mediaCarouselController.squishinessFraction = 0.0f
-        verifyNoMoreInteractions(mediaViewHolder)
-        verify(recommendationViewHolder.recommendations).bottom = 50
-
-        mediaCarouselController.squishinessFraction = 0.5f
-        verifyNoMoreInteractions(mediaViewHolder)
-        verify(recommendationViewHolder.recommendations).bottom = 75
-    }
-
     fun testMediaLoaded_ScrollToActivePlayer() {
         listener.value.onMediaDataLoaded("playing local",
                 null,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index cbe1186..3cad2a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -44,7 +44,6 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.media.MediaCarouselController;
 import com.android.systemui.media.MediaHost;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTileView;
@@ -87,7 +86,6 @@
     @Mock
     private QSLogger mQSLogger;
     private DumpManager mDumpManager = new DumpManager();
-    private MediaCarouselController mMediaCarouselController;
     @Mock
     QSTileImpl mQSTile;
     @Mock
@@ -110,9 +108,9 @@
         protected TestableQSPanelControllerBase(QSPanel view, QSTileHost host,
                 QSCustomizerController qsCustomizerController, MediaHost mediaHost,
                 MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
-                DumpManager dumpManager, MediaCarouselController mediaCarouselController) {
+                DumpManager dumpManager) {
             super(view, host, qsCustomizerController, true, mediaHost, metricsLogger, uiEventLogger,
-                    qsLogger, dumpManager, mediaCarouselController);
+                    qsLogger, dumpManager);
         }
 
         @Override
@@ -146,7 +144,7 @@
 
         mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
                 mQSCustomizerController, mMediaHost,
-                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController);
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
 
         mController.init();
         reset(mQSTileRevealController);
@@ -158,7 +156,7 @@
 
         QSPanelControllerBase<QSPanel> controller = new TestableQSPanelControllerBase(mQSPanel,
                 mQSTileHost, mQSCustomizerController, mMediaHost,
-                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController) {
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager) {
             @Override
             protected QSTileRevealController createTileRevealController() {
                 return mQSTileRevealController;
@@ -253,7 +251,7 @@
         when(mQSPanel.getDumpableTag()).thenReturn("QSPanelLandscape");
         mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
                 mQSCustomizerController, mMediaHost,
-                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController);
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
         mController.init();
 
         assertThat(mController.shouldUseHorizontalLayout()).isTrue();
@@ -262,7 +260,7 @@
         when(mQSPanel.getDumpableTag()).thenReturn("QSPanelPortrait");
         mController = new TestableQSPanelControllerBase(mQSPanel, mQSTileHost,
                 mQSCustomizerController, mMediaHost,
-                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager, mMediaCarouselController);
+                mMetricsLogger, mUiEventLogger, mQSLogger, mDumpManager);
         mController.init();
 
         assertThat(mController.shouldUseHorizontalLayout()).isFalse();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
index 98d499a..5eb9a98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -6,7 +6,6 @@
 import com.android.internal.logging.UiEventLogger
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.media.MediaCarouselController
 import com.android.systemui.media.MediaHost
 import com.android.systemui.media.MediaHostState
 import com.android.systemui.plugins.FalsingManager
@@ -41,7 +40,6 @@
     @Mock private lateinit var qsCustomizerController: QSCustomizerController
     @Mock private lateinit var qsTileRevealControllerFactory: QSTileRevealController.Factory
     @Mock private lateinit var dumpManager: DumpManager
-    @Mock private lateinit var mediaCarouselController: MediaCarouselController
     @Mock private lateinit var metricsLogger: MetricsLogger
     @Mock private lateinit var uiEventLogger: UiEventLogger
     @Mock private lateinit var qsLogger: QSLogger
@@ -78,7 +76,6 @@
             mediaHost,
             qsTileRevealControllerFactory,
             dumpManager,
-            mediaCarouselController,
             metricsLogger,
             uiEventLogger,
             qsLogger,
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 233c267..1c686c6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -726,7 +726,7 @@
         when(mSecurityController.isParentalControlsEnabled()).thenReturn(true);
         when(mSecurityController.getLabel(any())).thenReturn(PARENTAL_CONTROLS_LABEL);
 
-        View view = mFooterUtils.createDialogView();
+        View view = mFooterUtils.createDialogView(getContext());
         TextView textView = (TextView) view.findViewById(R.id.parental_controls_title);
         assertEquals(PARENTAL_CONTROLS_LABEL, textView.getText());
     }
@@ -749,7 +749,7 @@
         when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
                 .thenReturn(DEVICE_OWNER_TYPE_FINANCED);
 
-        View view = mFooterUtils.createDialogView();
+        View view = mFooterUtils.createDialogView(getContext());
 
         TextView managementSubtitle = view.findViewById(R.id.device_management_subtitle);
         assertEquals(View.VISIBLE, managementSubtitle.getVisibility());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 4af5b90..6af8e49 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -23,7 +23,6 @@
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
-import com.android.systemui.media.MediaCarouselController
 import com.android.systemui.media.MediaHost
 import com.android.systemui.media.MediaHostState
 import com.android.systemui.plugins.qs.QSTile
@@ -60,7 +59,6 @@
     @Mock private lateinit var tileLayout: TileLayout
     @Mock private lateinit var tileView: QSTileView
     @Captor private lateinit var captor: ArgumentCaptor<QSPanel.OnConfigurationChangedListener>
-    @Mock private lateinit var mediaCarouselController: MediaCarouselController
 
     private val uiEventLogger = UiEventLoggerFake()
     private val dumpManager = DumpManager()
@@ -90,8 +88,7 @@
                 metricsLogger,
                 uiEventLogger,
                 qsLogger,
-                dumpManager,
-                mediaCarouselController)
+                dumpManager)
 
         controller.init()
     }
@@ -158,8 +155,7 @@
         metricsLogger: MetricsLogger,
         uiEventLogger: UiEventLoggerFake,
         qsLogger: QSLogger,
-        dumpManager: DumpManager,
-        mediaCarouselController: MediaCarouselController
+        dumpManager: DumpManager
     ) :
         QuickQSPanelController(
             view,
@@ -171,8 +167,7 @@
             metricsLogger,
             uiEventLogger,
             qsLogger,
-            dumpManager,
-            mediaCarouselController) {
+            dumpManager) {
 
         private var rotation = RotationUtils.ROTATION_NONE
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
index eb907bd..39d89bf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickStatusBarHeaderControllerTest.kt
@@ -110,7 +110,7 @@
         `when`(qsCarrierGroupControllerBuilder.build()).thenReturn(qsCarrierGroupController)
         `when`(variableDateViewControllerFactory.create(any()))
                 .thenReturn(variableDateViewController)
-        `when`(iconManagerFactory.create(any())).thenReturn(iconManager)
+        `when`(iconManagerFactory.create(any(), any())).thenReturn(iconManager)
         `when`(view.resources).thenReturn(mContext.resources)
         `when`(view.isAttachedToWindow).thenReturn(true)
         `when`(view.context).thenReturn(context)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
index c448538..c76d9e7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
@@ -176,7 +176,7 @@
         }
         whenever(view.visibility).thenAnswer { _ -> viewVisibility }
 
-        whenever(iconManagerFactory.create(any())).thenReturn(iconManager)
+        whenever(iconManagerFactory.create(any(), any())).thenReturn(iconManager)
 
         whenever(featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)).thenReturn(true)
         whenever(featureFlags.isEnabled(Flags.NEW_HEADER)).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
index 5ecfc8eb..90ae693 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
@@ -97,7 +97,7 @@
         whenever(view.visibility).thenAnswer { _ -> viewVisibility }
         whenever(variableDateViewControllerFactory.create(any()))
             .thenReturn(variableDateViewController)
-        whenever(iconManagerFactory.create(any())).thenReturn(iconManager)
+        whenever(iconManagerFactory.create(any(), any())).thenReturn(iconManager)
         whenever(featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)).thenReturn(false)
         mLargeScreenShadeHeaderController = LargeScreenShadeHeaderController(
                 view,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
index 8bc438b..5fc09c7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/navigationbar/RegionSamplingHelperTest.kt
@@ -15,6 +15,7 @@
  */
 
 package com.android.systemui.shared.navigationbar
+
 import android.graphics.Rect
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
@@ -24,15 +25,23 @@
 import androidx.concurrent.futures.DirectExecutor
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
-import org.mockito.Mockito.*
-import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
@@ -99,4 +108,39 @@
         regionSamplingHelper.stopAndDestroy()
         verify(compositionListener).unregister(any())
     }
-}
\ No newline at end of file
+
+    @Test
+    fun testCompositionSamplingListener_has_nonEmptyRect() {
+        // simulate race condition
+        val fakeExecutor = FakeExecutor(FakeSystemClock()) // pass in as backgroundExecutor
+        val fakeSamplingCallback = mock(RegionSamplingHelper.SamplingCallback::class.java)
+
+        whenever(fakeSamplingCallback.isSamplingEnabled).thenReturn(true)
+        whenever(wrappedSurfaceControl.isValid).thenReturn(true)
+
+        regionSamplingHelper = object : RegionSamplingHelper(sampledView, fakeSamplingCallback,
+                DirectExecutor.INSTANCE, fakeExecutor, compositionListener) {
+            override fun wrap(stopLayerControl: SurfaceControl?): SurfaceControl {
+                return wrappedSurfaceControl
+            }
+        }
+        regionSamplingHelper.setWindowVisible(true)
+        regionSamplingHelper.start(Rect(0, 0, 100, 100))
+
+        // make sure background task is enqueued
+        assertThat(fakeExecutor.numPending()).isEqualTo(1)
+
+        // make sure regionSamplingHelper will have empty Rect
+        whenever(fakeSamplingCallback.getSampledRegion(any())).thenReturn(Rect(0, 0, 0, 0))
+        regionSamplingHelper.onLayoutChange(sampledView, 0, 0, 0, 0, 0, 0, 0, 0)
+
+        // resume running of background thread
+        fakeExecutor.runAllReady()
+
+        // grab Rect passed into compositionSamplingListener and make sure it's not empty
+        val argumentGrabber = argumentCaptor<Rect>()
+        verify(compositionListener).register(any(), anyInt(), eq(wrappedSurfaceControl),
+                argumentGrabber.capture())
+        assertThat(argumentGrabber.value.isEmpty).isFalse()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index ba5f503..cfaa470 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -135,7 +135,7 @@
 
         MockitoAnnotations.initMocks(this);
 
-        when(mIconManagerFactory.create(any())).thenReturn(mIconManager);
+        when(mIconManagerFactory.create(any(), any())).thenReturn(mIconManager);
 
         allowTestableLooperAsMainThread();
         TestableLooper.get(this).runWithLooper(() -> {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
index de7db74..34399b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarIconControllerTest.java
@@ -51,8 +51,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import javax.inject.Provider;
-
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
@@ -79,8 +77,9 @@
         LinearLayout layout = new LinearLayout(mContext);
         TestDarkIconManager manager = new TestDarkIconManager(
                 layout,
+                StatusBarLocation.HOME,
                 mock(StatusBarPipelineFlags.class),
-                () -> mock(WifiViewModel.class),
+                mock(WifiViewModel.class),
                 mMobileContextProvider,
                 mock(DarkIconDispatcher.class));
         testCallOnAdd_forManager(manager);
@@ -121,13 +120,15 @@
 
         TestDarkIconManager(
                 LinearLayout group,
+                StatusBarLocation location,
                 StatusBarPipelineFlags statusBarPipelineFlags,
-                Provider<WifiViewModel> wifiViewModelProvider,
+                WifiViewModel wifiViewModel,
                 MobileContextProvider contextProvider,
                 DarkIconDispatcher darkIconDispatcher) {
             super(group,
+                    location,
                     statusBarPipelineFlags,
-                    wifiViewModelProvider,
+                    wifiViewModel,
                     contextProvider,
                     darkIconDispatcher);
         }
@@ -165,8 +166,9 @@
     private static class TestIconManager extends IconManager implements TestableIconManager {
         TestIconManager(ViewGroup group, MobileContextProvider contextProvider) {
             super(group,
+                    StatusBarLocation.HOME,
                     mock(StatusBarPipelineFlags.class),
-                    () -> mock(WifiViewModel.class),
+                    mock(WifiViewModel.class),
                     contextProvider);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index ee4b9d9c..dcce61b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -26,7 +26,6 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -526,21 +525,4 @@
         mBouncerExpansionCallback.onVisibilityChanged(false);
         verify(mCentralSurfaces).setBouncerShowingOverDream(false);
     }
-
-    @Test
-    public void testSetDozing_Dozing() {
-        clearInvocations(mBouncer);
-        mStatusBarKeyguardViewManager.onDozingChanged(true);
-        // Once when shown and once with dozing changed.
-        verify(mBouncer, times(1)).hide(false);
-    }
-
-    @Test
-    public void testSetDozing_notDozing() {
-        mStatusBarKeyguardViewManager.onDozingChanged(true);
-        clearInvocations(mBouncer);
-        mStatusBarKeyguardViewManager.onDozingChanged(false);
-        // Once when shown and twice with dozing changed.
-        verify(mBouncer, times(1)).hide(false);
-    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 37c8f62..a3c6e95 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -431,7 +431,7 @@
         mOperatorNameViewControllerFactory = mock(OperatorNameViewController.Factory.class);
         when(mOperatorNameViewControllerFactory.create(any()))
                 .thenReturn(mOperatorNameViewController);
-        when(mIconManagerFactory.create(any())).thenReturn(mIconManager);
+        when(mIconManagerFactory.create(any(), any())).thenReturn(mIconManager);
         mSecureSettings = mock(SecureSettings.class);
 
         setUpNotificationIconAreaController();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
index 36be1be..0e75c74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
@@ -23,9 +23,16 @@
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.log.LogBufferFactory
 import com.android.systemui.log.LogcatEchoTracker
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logOutputChange
 import com.google.common.truth.Truth.assertThat
 import java.io.PrintWriter
 import java.io.StringWriter
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.runBlocking
 import org.junit.Test
 import org.mockito.Mockito
 import org.mockito.Mockito.mock
@@ -64,12 +71,70 @@
         assertThat(actualString).contains(expectedNetId)
     }
 
-    private val NET_1_ID = 100
-    private val NET_1 = com.android.systemui.util.mockito.mock<Network>().also {
-        Mockito.`when`(it.getNetId()).thenReturn(NET_1_ID)
+    @Test
+    fun logOutputChange_printsValuesAndNulls() = runBlocking(IMMEDIATE) {
+        val flow: Flow<Int?> = flowOf(1, null, 3)
+
+        val job = flow
+            .logOutputChange(logger, "testInts")
+            .launchIn(this)
+
+        val stringWriter = StringWriter()
+        buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+        val actualString = stringWriter.toString()
+
+        assertThat(actualString).contains("1")
+        assertThat(actualString).contains("null")
+        assertThat(actualString).contains("3")
+
+        job.cancel()
     }
-    private val NET_1_CAPS = NetworkCapabilities.Builder()
-        .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
-        .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
-        .build()
+
+    @Test
+    fun logInputChange_unit_printsInputName() = runBlocking(IMMEDIATE) {
+        val flow: Flow<Unit> = flowOf(Unit, Unit)
+
+        val job = flow
+            .logInputChange(logger, "testInputs")
+            .launchIn(this)
+
+        val stringWriter = StringWriter()
+        buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+        val actualString = stringWriter.toString()
+
+        assertThat(actualString).contains("testInputs")
+
+        job.cancel()
+    }
+
+    @Test
+    fun logInputChange_any_printsValuesAndNulls() = runBlocking(IMMEDIATE) {
+        val flow: Flow<Any?> = flowOf(null, 2, "threeString")
+
+        val job = flow
+            .logInputChange(logger, "testInputs")
+            .launchIn(this)
+
+        val stringWriter = StringWriter()
+        buffer.dump(PrintWriter(stringWriter), tailLength = 0)
+        val actualString = stringWriter.toString()
+
+        assertThat(actualString).contains("null")
+        assertThat(actualString).contains("2")
+        assertThat(actualString).contains("threeString")
+
+        job.cancel()
+    }
+
+    companion object {
+        private const val NET_1_ID = 100
+        private val NET_1 = com.android.systemui.util.mockito.mock<Network>().also {
+            Mockito.`when`(it.getNetId()).thenReturn(NET_1_ID)
+        }
+        private val NET_1_CAPS = NetworkCapabilities.Builder()
+            .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
+            .build()
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
index 6b8d4aa..f751afc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/FakeWifiRepository.kt
@@ -16,20 +16,27 @@
 
 package com.android.systemui.statusbar.pipeline.wifi.data.repository
 
-import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
-import kotlinx.coroutines.flow.Flow
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
 
 /** Fake implementation of [WifiRepository] exposing set methods for all the flows. */
 class FakeWifiRepository : WifiRepository {
+    private val _isWifiEnabled: MutableStateFlow<Boolean> = MutableStateFlow(false)
+    override val isWifiEnabled: StateFlow<Boolean> = _isWifiEnabled
+
     private val _wifiNetwork: MutableStateFlow<WifiNetworkModel> =
         MutableStateFlow(WifiNetworkModel.Inactive)
-    override val wifiNetwork: Flow<WifiNetworkModel> = _wifiNetwork
+    override val wifiNetwork: StateFlow<WifiNetworkModel> = _wifiNetwork
 
     private val _wifiActivity = MutableStateFlow(ACTIVITY_DEFAULT)
-    override val wifiActivity: Flow<WifiActivityModel> = _wifiActivity
+    override val wifiActivity: StateFlow<WifiActivityModel> = _wifiActivity
+
+    fun setIsWifiEnabled(enabled: Boolean) {
+        _isWifiEnabled.value = enabled
+    }
 
     fun setWifiNetwork(wifiNetworkModel: WifiNetworkModel) {
         _wifiNetwork.value = wifiNetworkModel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
index d070ba0..0ba0bd6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
@@ -28,15 +28,17 @@
 import android.net.wifi.WifiManager.TrafficStateCallback
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.WIFI_NETWORK_DEFAULT
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth.assertThat
 import java.util.concurrent.Executor
@@ -44,23 +46,28 @@
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.runBlocking
 import org.junit.After
 import org.junit.Before
 import org.junit.Test
+import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 class WifiRepositoryImplTest : SysuiTestCase() {
 
     private lateinit var underTest: WifiRepositoryImpl
 
+    @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
     @Mock private lateinit var logger: ConnectivityPipelineLogger
     @Mock private lateinit var connectivityManager: ConnectivityManager
     @Mock private lateinit var wifiManager: WifiManager
@@ -70,16 +77,17 @@
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
+        whenever(
+            broadcastDispatcher.broadcastFlow(
+                any(),
+                nullable(),
+                anyInt(),
+                nullable(),
+            )
+        ).thenReturn(flowOf(Unit))
         executor = FakeExecutor(FakeSystemClock())
         scope = CoroutineScope(IMMEDIATE)
-
-        underTest = WifiRepositoryImpl(
-            connectivityManager,
-            logger,
-            executor,
-            scope,
-            wifiManager,
-        )
+        underTest = createRepo()
     }
 
     @After
@@ -88,6 +96,132 @@
     }
 
     @Test
+    fun isWifiEnabled_nullWifiManager_getsFalse() = runBlocking(IMMEDIATE) {
+        underTest = createRepo(wifiManagerToUse = null)
+
+        assertThat(underTest.isWifiEnabled.value).isFalse()
+    }
+
+    @Test
+    fun isWifiEnabled_initiallyGetsWifiManagerValue() = runBlocking(IMMEDIATE) {
+        whenever(wifiManager.isWifiEnabled).thenReturn(true)
+
+        underTest = createRepo()
+
+        assertThat(underTest.isWifiEnabled.value).isTrue()
+    }
+
+    @Test
+    fun isWifiEnabled_networkCapabilitiesChanged_valueUpdated() = runBlocking(IMMEDIATE) {
+        // We need to call launch on the flows so that they start updating
+        val networkJob = underTest.wifiNetwork.launchIn(this)
+        val enabledJob = underTest.isWifiEnabled.launchIn(this)
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(true)
+        getNetworkCallback().onCapabilitiesChanged(
+            NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)
+        )
+
+        assertThat(underTest.isWifiEnabled.value).isTrue()
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(false)
+        getNetworkCallback().onCapabilitiesChanged(
+            NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)
+        )
+
+        assertThat(underTest.isWifiEnabled.value).isFalse()
+
+        networkJob.cancel()
+        enabledJob.cancel()
+    }
+
+    @Test
+    fun isWifiEnabled_networkLost_valueUpdated() = runBlocking(IMMEDIATE) {
+        // We need to call launch on the flows so that they start updating
+        val networkJob = underTest.wifiNetwork.launchIn(this)
+        val enabledJob = underTest.isWifiEnabled.launchIn(this)
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(true)
+        getNetworkCallback().onLost(NETWORK)
+
+        assertThat(underTest.isWifiEnabled.value).isTrue()
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(false)
+        getNetworkCallback().onLost(NETWORK)
+
+        assertThat(underTest.isWifiEnabled.value).isFalse()
+
+        networkJob.cancel()
+        enabledJob.cancel()
+    }
+
+    @Test
+    fun isWifiEnabled_intentsReceived_valueUpdated() = runBlocking(IMMEDIATE) {
+        val intentFlow = MutableSharedFlow<Unit>()
+        whenever(
+            broadcastDispatcher.broadcastFlow(
+                any(),
+                nullable(),
+                anyInt(),
+                nullable(),
+            )
+        ).thenReturn(intentFlow)
+        underTest = createRepo()
+
+        val job = underTest.isWifiEnabled.launchIn(this)
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(true)
+        intentFlow.emit(Unit)
+
+        assertThat(underTest.isWifiEnabled.value).isTrue()
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(false)
+        intentFlow.emit(Unit)
+
+        assertThat(underTest.isWifiEnabled.value).isFalse()
+
+        job.cancel()
+    }
+
+    @Test
+    fun isWifiEnabled_bothIntentAndNetworkUpdates_valueAlwaysUpdated() = runBlocking(IMMEDIATE) {
+        val intentFlow = MutableSharedFlow<Unit>()
+        whenever(
+            broadcastDispatcher.broadcastFlow(
+                any(),
+                nullable(),
+                anyInt(),
+                nullable(),
+            )
+        ).thenReturn(intentFlow)
+        underTest = createRepo()
+
+        val networkJob = underTest.wifiNetwork.launchIn(this)
+        val enabledJob = underTest.isWifiEnabled.launchIn(this)
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(false)
+        intentFlow.emit(Unit)
+        assertThat(underTest.isWifiEnabled.value).isFalse()
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(true)
+        getNetworkCallback().onLost(NETWORK)
+        assertThat(underTest.isWifiEnabled.value).isTrue()
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(false)
+        getNetworkCallback().onCapabilitiesChanged(
+            NETWORK, createWifiNetworkCapabilities(PRIMARY_WIFI_INFO)
+        )
+        assertThat(underTest.isWifiEnabled.value).isFalse()
+
+        whenever(wifiManager.isWifiEnabled).thenReturn(true)
+        intentFlow.emit(Unit)
+        assertThat(underTest.isWifiEnabled.value).isTrue()
+
+        networkJob.cancel()
+        enabledJob.cancel()
+    }
+
+    @Test
     fun wifiNetwork_initiallyGetsDefault() = runBlocking(IMMEDIATE) {
         var latest: WifiNetworkModel? = null
         val job = underTest
@@ -509,13 +643,7 @@
 
     @Test
     fun wifiActivity_nullWifiManager_receivesDefault() = runBlocking(IMMEDIATE) {
-        underTest = WifiRepositoryImpl(
-            connectivityManager,
-            logger,
-            executor,
-            scope,
-            wifiManager = null,
-        )
+        underTest = createRepo(wifiManagerToUse = null)
 
         var latest: WifiActivityModel? = null
         val job = underTest
@@ -594,6 +722,17 @@
         job.cancel()
     }
 
+    private fun createRepo(wifiManagerToUse: WifiManager? = wifiManager): WifiRepositoryImpl {
+        return WifiRepositoryImpl(
+            broadcastDispatcher,
+            connectivityManager,
+            logger,
+            executor,
+            scope,
+            wifiManagerToUse,
+        )
+    }
+
     private fun getTrafficStateCallback(): TrafficStateCallback {
         val callbackCaptor = argumentCaptor<TrafficStateCallback>()
         verify(wifiManager).registerTrafficStateCallback(any(), callbackCaptor.capture())
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
index e896749..39b886a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
@@ -16,13 +16,14 @@
 
 package com.android.systemui.statusbar.pipeline.wifi.domain.interactor
 
+import android.net.wifi.WifiManager
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
 import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
-import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -50,172 +51,129 @@
     }
 
     @Test
-    fun hasActivityIn_noInOrOut_outputsFalse() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
-        )
-
-        var latest: Boolean? = null
-        val job = underTest
-                .hasActivityIn
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isFalse()
-
-        job.cancel()
-    }
-
-    @Test
-    fun hasActivityIn_onlyOut_outputsFalse() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
-        )
-
-        var latest: Boolean? = null
-        val job = underTest
-                .hasActivityIn
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isFalse()
-
-        job.cancel()
-    }
-
-    @Test
-    fun hasActivityIn_onlyIn_outputsTrue() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
-        )
-
-        var latest: Boolean? = null
-        val job = underTest
-                .hasActivityIn
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isTrue()
-
-        job.cancel()
-    }
-
-    @Test
-    fun hasActivityIn_inAndOut_outputsTrue() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
-        )
-
-        var latest: Boolean? = null
-        val job = underTest
-                .hasActivityIn
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isTrue()
-
-        job.cancel()
-    }
-
-    @Test
-    fun hasActivityIn_ssidNull_outputsFalse() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(networkId = 1, ssid = null))
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
-        )
-
-        var latest: Boolean? = null
-        val job = underTest
-                .hasActivityIn
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isFalse()
-
-        job.cancel()
-    }
-
-    @Test
-    fun hasActivityIn_inactiveNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
+    fun ssid_inactiveNetwork_outputsNull() = runBlocking(IMMEDIATE) {
         wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
-        )
 
-        var latest: Boolean? = null
+        var latest: String? = "default"
         val job = underTest
-            .hasActivityIn
+            .ssid
             .onEach { latest = it }
             .launchIn(this)
 
-        assertThat(latest).isFalse()
+        assertThat(latest).isNull()
 
         job.cancel()
     }
 
     @Test
-    fun hasActivityIn_carrierMergedNetwork_outputsFalse() = runBlocking(IMMEDIATE) {
+    fun ssid_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
         wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
-        )
 
-        var latest: Boolean? = null
+        var latest: String? = "default"
         val job = underTest
-            .hasActivityIn
+            .ssid
             .onEach { latest = it }
             .launchIn(this)
 
-        assertThat(latest).isFalse()
+        assertThat(latest).isNull()
 
         job.cancel()
     }
 
     @Test
-    fun hasActivityIn_multipleChanges_multipleOutputChanges() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(VALID_WIFI_NETWORK_MODEL)
+    fun ssid_isPasspointAccessPoint_outputsPasspointName() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
+            networkId = 1,
+            isPasspointAccessPoint = true,
+            passpointProviderFriendlyName = "friendly",
+        ))
 
+        var latest: String? = null
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isEqualTo("friendly")
+
+        job.cancel()
+    }
+
+    @Test
+    fun ssid_isOnlineSignUpForPasspoint_outputsPasspointName() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
+            networkId = 1,
+            isOnlineSignUpForPasspointAccessPoint = true,
+            passpointProviderFriendlyName = "friendly",
+        ))
+
+        var latest: String? = null
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isEqualTo("friendly")
+
+        job.cancel()
+    }
+
+    @Test
+    fun ssid_unknownSsid_outputsNull() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
+            networkId = 1,
+            ssid = WifiManager.UNKNOWN_SSID,
+        ))
+
+        var latest: String? = "default"
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isNull()
+
+        job.cancel()
+    }
+
+    @Test
+    fun ssid_validSsid_outputsSsid() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
+            networkId = 1,
+            ssid = "MyAwesomeWifiNetwork",
+        ))
+
+        var latest: String? = null
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isEqualTo("MyAwesomeWifiNetwork")
+
+        job.cancel()
+    }
+
+    @Test
+    fun isEnabled_matchesRepoIsEnabled() = runBlocking(IMMEDIATE) {
         var latest: Boolean? = null
         val job = underTest
-                .hasActivityIn
-                .onEach { latest = it }
-                .launchIn(this)
+            .isEnabled
+            .onEach { latest = it }
+            .launchIn(this)
 
-        // Conduct a series of changes and verify we catch each of them in succession
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
-        )
+        wifiRepository.setIsWifiEnabled(true)
         yield()
         assertThat(latest).isTrue()
 
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
-        )
+        wifiRepository.setIsWifiEnabled(false)
         yield()
         assertThat(latest).isFalse()
 
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
-        )
+        wifiRepository.setIsWifiEnabled(true)
         yield()
         assertThat(latest).isTrue()
 
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
-        )
-        yield()
-        assertThat(latest).isTrue()
-
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
-        )
-        yield()
-        assertThat(latest).isFalse()
-
         job.cancel()
     }
 
@@ -242,6 +200,32 @@
     }
 
     @Test
+    fun activity_matchesRepoWifiActivity() = runBlocking(IMMEDIATE) {
+        var latest: WifiActivityModel? = null
+        val job = underTest
+            .activity
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity1 = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity1)
+        yield()
+        assertThat(latest).isEqualTo(activity1)
+
+        val activity2 = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity2)
+        yield()
+        assertThat(latest).isEqualTo(activity2)
+
+        val activity3 = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity3)
+        yield()
+        assertThat(latest).isEqualTo(activity3)
+
+        job.cancel()
+    }
+
+    @Test
     fun isForceHidden_repoHasWifiHidden_outputsTrue() = runBlocking(IMMEDIATE) {
         connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
 
@@ -270,10 +254,6 @@
 
         job.cancel()
     }
-
-    companion object {
-        val VALID_WIFI_NETWORK_MODEL = WifiNetworkModel.Active(networkId = 1, ssid = "AB")
-    }
 }
 
 private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
index 3c200a5..4efb135 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
@@ -16,38 +16,225 @@
 
 package com.android.systemui.statusbar.pipeline.wifi.ui.view
 
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
+import android.testing.ViewUtils
+import android.view.View
 import androidx.test.filters.SmallTest
+import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.lifecycle.InstantTaskExecutorRule
-import com.android.systemui.util.Assert
-import com.android.systemui.util.mockito.mock
+import com.android.systemui.statusbar.StatusBarIconView.STATE_DOT
+import com.android.systemui.statusbar.StatusBarIconView.STATE_HIDDEN
+import com.android.systemui.statusbar.StatusBarIconView.STATE_ICON
+import com.android.systemui.statusbar.phone.StatusBarLocation
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
+import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
+import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
 
 @SmallTest
-@RunWith(JUnit4::class)
-@RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper(setAsMainLooper = true)
 class ModernStatusBarWifiViewTest : SysuiTestCase() {
 
+    private lateinit var testableLooper: TestableLooper
+
+    @Mock
+    private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
+    @Mock
+    private lateinit var logger: ConnectivityPipelineLogger
+    @Mock
+    private lateinit var connectivityConstants: ConnectivityConstants
+    @Mock
+    private lateinit var wifiConstants: WifiConstants
+    private lateinit var connectivityRepository: FakeConnectivityRepository
+    private lateinit var wifiRepository: FakeWifiRepository
+    private lateinit var interactor: WifiInteractor
+    private lateinit var viewModel: WifiViewModel
+    private lateinit var scope: CoroutineScope
+
     @JvmField @Rule
     val instantTaskExecutor = InstantTaskExecutorRule()
 
     @Before
     fun setUp() {
-        Assert.setTestThread(Thread.currentThread())
+        MockitoAnnotations.initMocks(this)
+        testableLooper = TestableLooper.get(this)
+
+        connectivityRepository = FakeConnectivityRepository()
+        wifiRepository = FakeWifiRepository()
+        wifiRepository.setIsWifiEnabled(true)
+        interactor = WifiInteractor(connectivityRepository, wifiRepository)
+        scope = CoroutineScope(Dispatchers.Unconfined)
+        viewModel = WifiViewModel(
+            connectivityConstants,
+            context,
+            logger,
+            interactor,
+            scope,
+            statusBarPipelineFlags,
+            wifiConstants,
+        )
     }
 
     @Test
     fun constructAndBind_hasCorrectSlot() {
         val view = ModernStatusBarWifiView.constructAndBind(
-            context, "slotName", mock()
+            context, "slotName", viewModel, StatusBarLocation.HOME
         )
 
         assertThat(view.slot).isEqualTo("slotName")
     }
+
+    @Test
+    fun getVisibleState_icon_returnsIcon() {
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        view.setVisibleState(STATE_ICON, /* animate= */ false)
+
+        assertThat(view.visibleState).isEqualTo(STATE_ICON)
+    }
+
+    @Test
+    fun getVisibleState_dot_returnsDot() {
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        view.setVisibleState(STATE_DOT, /* animate= */ false)
+
+        assertThat(view.visibleState).isEqualTo(STATE_DOT)
+    }
+
+    @Test
+    fun getVisibleState_hidden_returnsHidden() {
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        view.setVisibleState(STATE_HIDDEN, /* animate= */ false)
+
+        assertThat(view.visibleState).isEqualTo(STATE_HIDDEN)
+    }
+
+    // Note: The following tests are more like integration tests, since they stand up a full
+    // [WifiViewModel] and test the interactions between the view, view-binder, and view-model.
+
+    @Test
+    fun setVisibleState_icon_iconShownDotHidden() {
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        view.setVisibleState(STATE_ICON, /* animate= */ false)
+
+        ViewUtils.attachView(view)
+        testableLooper.processAllMessages()
+
+        assertThat(view.getIconGroupView().visibility).isEqualTo(View.VISIBLE)
+        assertThat(view.getDotView().visibility).isEqualTo(View.GONE)
+
+        ViewUtils.detachView(view)
+    }
+
+    @Test
+    fun setVisibleState_dot_iconHiddenDotShown() {
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        view.setVisibleState(STATE_DOT, /* animate= */ false)
+
+        ViewUtils.attachView(view)
+        testableLooper.processAllMessages()
+
+        assertThat(view.getIconGroupView().visibility).isEqualTo(View.GONE)
+        assertThat(view.getDotView().visibility).isEqualTo(View.VISIBLE)
+
+        ViewUtils.detachView(view)
+    }
+
+    @Test
+    fun setVisibleState_hidden_iconAndDotHidden() {
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        view.setVisibleState(STATE_HIDDEN, /* animate= */ false)
+
+        ViewUtils.attachView(view)
+        testableLooper.processAllMessages()
+
+        assertThat(view.getIconGroupView().visibility).isEqualTo(View.GONE)
+        assertThat(view.getDotView().visibility).isEqualTo(View.GONE)
+
+        ViewUtils.detachView(view)
+    }
+
+    @Test
+    fun isIconVisible_notEnabled_outputsFalse() {
+        wifiRepository.setIsWifiEnabled(false)
+        wifiRepository.setWifiNetwork(
+            WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2)
+        )
+
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        ViewUtils.attachView(view)
+        testableLooper.processAllMessages()
+
+        assertThat(view.isIconVisible).isFalse()
+
+        ViewUtils.detachView(view)
+    }
+
+    @Test
+    fun isIconVisible_enabled_outputsTrue() {
+        wifiRepository.setIsWifiEnabled(true)
+        wifiRepository.setWifiNetwork(
+            WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2)
+        )
+
+        val view = ModernStatusBarWifiView.constructAndBind(
+            context, SLOT_NAME, viewModel, StatusBarLocation.HOME
+        )
+
+        ViewUtils.attachView(view)
+        testableLooper.processAllMessages()
+
+        assertThat(view.isIconVisible).isTrue()
+
+        ViewUtils.detachView(view)
+    }
+
+    private fun View.getIconGroupView(): View {
+        return this.requireViewById(R.id.wifi_group)
+    }
+
+    private fun View.getDotView(): View {
+        return this.requireViewById(R.id.status_bar_dot)
+    }
 }
+
+private const val SLOT_NAME = "TestSlotName"
+private const val NETWORK_ID = 200
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
new file mode 100644
index 0000000..929e529
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
@@ -0,0 +1,326 @@
+/*
+ * 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.statusbar.pipeline.wifi.ui.viewmodel
+
+import android.content.Context
+import androidx.annotation.DrawableRes
+import androidx.test.filters.SmallTest
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_NO_CONNECTION
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.statusbar.connectivity.WifiIcons
+import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
+import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
+import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
+import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
+import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel.Companion.NO_INTERNET
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+import org.mockito.Mock
+import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(Parameterized::class)
+internal class WifiViewModelIconParameterizedTest(private val testCase: TestCase) :
+    SysuiTestCase() {
+
+    private lateinit var underTest: WifiViewModel
+
+    @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
+    @Mock private lateinit var logger: ConnectivityPipelineLogger
+    @Mock private lateinit var connectivityConstants: ConnectivityConstants
+    @Mock private lateinit var wifiConstants: WifiConstants
+    private lateinit var connectivityRepository: FakeConnectivityRepository
+    private lateinit var wifiRepository: FakeWifiRepository
+    private lateinit var interactor: WifiInteractor
+    private lateinit var scope: CoroutineScope
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        connectivityRepository = FakeConnectivityRepository()
+        wifiRepository = FakeWifiRepository()
+        wifiRepository.setIsWifiEnabled(true)
+        interactor = WifiInteractor(connectivityRepository, wifiRepository)
+        scope = CoroutineScope(IMMEDIATE)
+    }
+
+    @After
+    fun tearDown() {
+        scope.cancel()
+    }
+
+    @Test
+    fun wifiIcon() =
+        runBlocking(IMMEDIATE) {
+            wifiRepository.setIsWifiEnabled(testCase.enabled)
+            connectivityRepository.setForceHiddenIcons(
+                if (testCase.forceHidden) {
+                    setOf(ConnectivitySlot.WIFI)
+                } else {
+                    setOf()
+                }
+            )
+            whenever(wifiConstants.alwaysShowIconIfEnabled)
+                .thenReturn(testCase.alwaysShowIconWhenEnabled)
+            whenever(connectivityConstants.hasDataCapabilities)
+                .thenReturn(testCase.hasDataCapabilities)
+            underTest =
+                WifiViewModel(
+                    connectivityConstants,
+                    context,
+                    logger,
+                    interactor,
+                    scope,
+                    statusBarPipelineFlags,
+                    wifiConstants,
+                )
+
+            val iconFlow = underTest.home.wifiIcon
+            val job = iconFlow.launchIn(this)
+
+            // WHEN we set a certain network
+            wifiRepository.setWifiNetwork(testCase.network)
+            yield()
+
+            // THEN we get the expected icon
+            assertThat(iconFlow.value?.res).isEqualTo(testCase.expected?.iconResource)
+            val expectedContentDescription =
+                if (testCase.expected == null) {
+                    null
+                } else {
+                    testCase.expected.contentDescription.invoke(context)
+                }
+            assertThat(iconFlow.value?.contentDescription?.getAsString())
+                .isEqualTo(expectedContentDescription)
+
+            job.cancel()
+        }
+
+    private fun ContentDescription.getAsString(): String? {
+        return when (this) {
+            is ContentDescription.Loaded -> this.description
+            is ContentDescription.Resource -> context.getString(this.res)
+        }
+    }
+
+    internal data class Expected(
+        /** The resource that should be used for the icon. */
+        @DrawableRes val iconResource: Int,
+
+        /** A function that, given a context, calculates the correct content description string. */
+        val contentDescription: (Context) -> String,
+    )
+
+    // Note: We use default values for the boolean parameters to reflect a "typical configuration"
+    //   for wifi. This allows each TestCase to only define the parameter values that are critical
+    //   for the test function.
+    internal data class TestCase(
+        val enabled: Boolean = true,
+        val forceHidden: Boolean = false,
+        val alwaysShowIconWhenEnabled: Boolean = false,
+        val hasDataCapabilities: Boolean = true,
+        val network: WifiNetworkModel,
+
+        /** The expected output. Null if we expect the output to be null. */
+        val expected: Expected?
+    )
+
+    companion object {
+        @Parameters(name = "{0}")
+        @JvmStatic
+        fun data(): Collection<TestCase> =
+            listOf(
+                // Enabled = false => no networks shown
+                TestCase(
+                    enabled = false,
+                    network = WifiNetworkModel.CarrierMerged,
+                    expected = null,
+                ),
+                TestCase(
+                    enabled = false,
+                    network = WifiNetworkModel.Inactive,
+                    expected = null,
+                ),
+                TestCase(
+                    enabled = false,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 1),
+                    expected = null,
+                ),
+                TestCase(
+                    enabled = false,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 3),
+                    expected = null,
+                ),
+
+                // forceHidden = true => no networks shown
+                TestCase(
+                    forceHidden = true,
+                    network = WifiNetworkModel.CarrierMerged,
+                    expected = null,
+                ),
+                TestCase(
+                    forceHidden = true,
+                    network = WifiNetworkModel.Inactive,
+                    expected = null,
+                ),
+                TestCase(
+                    enabled = false,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 2),
+                    expected = null,
+                ),
+                TestCase(
+                    forceHidden = true,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 1),
+                    expected = null,
+                ),
+
+                // alwaysShowIconWhenEnabled = true => all Inactive and Active networks shown
+                TestCase(
+                    alwaysShowIconWhenEnabled = true,
+                    network = WifiNetworkModel.Inactive,
+                    expected =
+                        Expected(
+                            iconResource = WifiIcons.WIFI_NO_NETWORK,
+                            contentDescription = { context ->
+                                "${context.getString(WIFI_NO_CONNECTION)}," +
+                                    context.getString(NO_INTERNET)
+                            }
+                        ),
+                ),
+                TestCase(
+                    alwaysShowIconWhenEnabled = true,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 4),
+                    expected =
+                        Expected(
+                            iconResource = WIFI_NO_INTERNET_ICONS[4],
+                            contentDescription = { context ->
+                                "${context.getString(WIFI_CONNECTION_STRENGTH[4])}," +
+                                    context.getString(NO_INTERNET)
+                            }
+                        ),
+                ),
+                TestCase(
+                    alwaysShowIconWhenEnabled = true,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 2),
+                    expected =
+                        Expected(
+                            iconResource = WIFI_FULL_ICONS[2],
+                            contentDescription = { context ->
+                                context.getString(WIFI_CONNECTION_STRENGTH[2])
+                            }
+                        ),
+                ),
+
+                // hasDataCapabilities = false => all Inactive and Active networks shown
+                TestCase(
+                    hasDataCapabilities = false,
+                    network = WifiNetworkModel.Inactive,
+                    expected =
+                        Expected(
+                            iconResource = WifiIcons.WIFI_NO_NETWORK,
+                            contentDescription = { context ->
+                                "${context.getString(WIFI_NO_CONNECTION)}," +
+                                    context.getString(NO_INTERNET)
+                            }
+                        ),
+                ),
+                TestCase(
+                    hasDataCapabilities = false,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 2),
+                    expected =
+                        Expected(
+                            iconResource = WIFI_NO_INTERNET_ICONS[2],
+                            contentDescription = { context ->
+                                "${context.getString(WIFI_CONNECTION_STRENGTH[2])}," +
+                                    context.getString(NO_INTERNET)
+                            }
+                        ),
+                ),
+                TestCase(
+                    hasDataCapabilities = false,
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 0),
+                    expected =
+                        Expected(
+                            iconResource = WIFI_FULL_ICONS[0],
+                            contentDescription = { context ->
+                                context.getString(WIFI_CONNECTION_STRENGTH[0])
+                            }
+                        ),
+                ),
+
+                // network = CarrierMerged => not shown
+                TestCase(
+                    network = WifiNetworkModel.CarrierMerged,
+                    expected = null,
+                ),
+
+                // network = Inactive => not shown
+                TestCase(
+                    network = WifiNetworkModel.Inactive,
+                    expected = null,
+                ),
+
+                // network = Active & validated = false => not shown
+                TestCase(
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = false, level = 3),
+                    expected = null,
+                ),
+
+                // network = Active & validated = true => shown
+                TestCase(
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 4),
+                    expected =
+                        Expected(
+                            iconResource = WIFI_FULL_ICONS[4],
+                            contentDescription = { context ->
+                                context.getString(WIFI_CONNECTION_STRENGTH[4])
+                            }
+                        ),
+                ),
+
+                // network has null level => not shown
+                TestCase(
+                    network = WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = null),
+                    expected = null,
+                ),
+            )
+    }
+}
+
+private val IMMEDIATE = Dispatchers.Main.immediate
+private const val NETWORK_ID = 789
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index 43103a0..3169eef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -17,37 +17,34 @@
 package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
 
 import androidx.test.filters.SmallTest
-import com.android.settingslib.AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH
-import com.android.settingslib.AccessibilityContentDescriptions.WIFI_NO_CONNECTION
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
-import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
-import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_NETWORK
 import com.android.systemui.statusbar.pipeline.StatusBarPipelineFlags
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
 import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
-import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiActivityModel
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
-import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel.Companion.NO_INTERNET
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.cancel
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.yield
+import org.junit.After
 import org.junit.Before
 import org.junit.Test
 import org.mockito.Mock
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
 
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
 @OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 class WifiViewModelTest : SysuiTestCase() {
@@ -56,236 +53,426 @@
 
     @Mock private lateinit var statusBarPipelineFlags: StatusBarPipelineFlags
     @Mock private lateinit var logger: ConnectivityPipelineLogger
-    @Mock private lateinit var constants: WifiConstants
+    @Mock private lateinit var connectivityConstants: ConnectivityConstants
+    @Mock private lateinit var wifiConstants: WifiConstants
     private lateinit var connectivityRepository: FakeConnectivityRepository
     private lateinit var wifiRepository: FakeWifiRepository
     private lateinit var interactor: WifiInteractor
+    private lateinit var scope: CoroutineScope
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         connectivityRepository = FakeConnectivityRepository()
         wifiRepository = FakeWifiRepository()
+        wifiRepository.setIsWifiEnabled(true)
         interactor = WifiInteractor(connectivityRepository, wifiRepository)
-
-        underTest = WifiViewModel(
-            statusBarPipelineFlags,
-            constants,
-            context,
-            logger,
-            interactor
-        )
+        scope = CoroutineScope(IMMEDIATE)
+        createAndSetViewModel()
     }
 
-    @Test
-    fun wifiIcon_forceHidden_outputsNull() = runBlocking(IMMEDIATE) {
-        connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = 2))
+    @After
+    fun tearDown() {
+        scope.cancel()
+    }
 
-        var latest: Icon? = null
-        val job = underTest
+    // Note on testing: [WifiViewModel] exposes 3 different instances of
+    // [LocationBasedWifiViewModel]. In practice, these 3 different instances will get the exact
+    // same data for icon, activity, etc. flows. So, most of these tests will test just one of the
+    // instances. There are also some tests that verify all 3 instances received the same data.
+
+    @Test
+    fun wifiIcon_allLocationViewModelsReceiveSameData() = runBlocking(IMMEDIATE) {
+        var latestHome: Icon? = null
+        val jobHome = underTest
+            .home
             .wifiIcon
-            .onEach { latest = it }
+            .onEach { latestHome = it }
             .launchIn(this)
 
-        assertThat(latest).isNull()
-
-        job.cancel()
-    }
-
-    @Test
-    fun wifiIcon_notForceHidden_outputsVisible() = runBlocking(IMMEDIATE) {
-        connectivityRepository.setForceHiddenIcons(setOf())
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = 2))
-
-        var latest: Icon? = null
-        val job = underTest
+        var latestKeyguard: Icon? = null
+        val jobKeyguard = underTest
+            .keyguard
             .wifiIcon
-            .onEach { latest = it }
+            .onEach { latestKeyguard = it }
             .launchIn(this)
 
-        assertThat(latest).isInstanceOf(Icon.Resource::class.java)
-
-        job.cancel()
-    }
-
-    @Test
-    fun wifiIcon_inactiveNetwork_outputsNoNetworkIcon() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
-
-        var latest: Icon? = null
-        val job = underTest
-                .wifiIcon
-                .onEach { latest = it }
-                .launchIn(this)
-
-        assertThat(latest).isInstanceOf(Icon.Resource::class.java)
-        val icon = latest as Icon.Resource
-        assertThat(icon.res).isEqualTo(WIFI_NO_NETWORK)
-        assertThat(icon.contentDescription?.getAsString())
-            .contains(context.getString(WIFI_NO_CONNECTION))
-        assertThat(icon.contentDescription?.getAsString())
-            .contains(context.getString(NO_INTERNET))
-
-        job.cancel()
-    }
-
-    @Test
-    fun wifiIcon_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
-
-        var latest: Icon? = null
-        val job = underTest
+        var latestQs: Icon? = null
+        val jobQs = underTest
+            .qs
             .wifiIcon
-            .onEach { latest = it }
+            .onEach { latestQs = it }
             .launchIn(this)
 
-        assertThat(latest).isNull()
-
-        job.cancel()
-    }
-
-    @Test
-    fun wifiIcon_isActiveNullLevel_outputsNull() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, level = null))
-
-        var latest: Icon? = null
-        val job = underTest
-            .wifiIcon
-            .onEach { latest = it }
-            .launchIn(this)
-
-        assertThat(latest).isNull()
-
-        job.cancel()
-    }
-
-    @Test
-    fun wifiIcon_isActiveAndValidated_level1_outputsFull1Icon() = runBlocking(IMMEDIATE) {
-        val level = 1
-
         wifiRepository.setWifiNetwork(
-                WifiNetworkModel.Active(
-                        NETWORK_ID,
-                        isValidated = true,
-                        level = level
-                )
-        )
-
-        var latest: Icon? = null
-        val job = underTest
-            .wifiIcon
-            .onEach { latest = it }
-            .launchIn(this)
-
-        assertThat(latest).isInstanceOf(Icon.Resource::class.java)
-        val icon = latest as Icon.Resource
-        assertThat(icon.res).isEqualTo(WIFI_FULL_ICONS[level])
-        assertThat(icon.contentDescription?.getAsString())
-            .contains(context.getString(WIFI_CONNECTION_STRENGTH[level]))
-        assertThat(icon.contentDescription?.getAsString())
-            .doesNotContain(context.getString(NO_INTERNET))
-
-        job.cancel()
-    }
-
-    @Test
-    fun wifiIcon_isActiveAndNotValidated_level4_outputsEmpty4Icon() = runBlocking(IMMEDIATE) {
-        val level = 4
-
-        wifiRepository.setWifiNetwork(
-                WifiNetworkModel.Active(
-                        NETWORK_ID,
-                        isValidated = false,
-                        level = level
-                )
-        )
-
-        var latest: Icon? = null
-        val job = underTest
-            .wifiIcon
-            .onEach { latest = it }
-            .launchIn(this)
-
-        assertThat(latest).isInstanceOf(Icon.Resource::class.java)
-        val icon = latest as Icon.Resource
-        assertThat(icon.res).isEqualTo(WIFI_NO_INTERNET_ICONS[level])
-        assertThat(icon.contentDescription?.getAsString())
-            .contains(context.getString(WIFI_CONNECTION_STRENGTH[level]))
-        assertThat(icon.contentDescription?.getAsString())
-            .contains(context.getString(NO_INTERNET))
-
-        job.cancel()
-    }
-
-    @Test
-    fun activityInVisible_showActivityConfigFalse_outputsFalse() = runBlocking(IMMEDIATE) {
-        whenever(constants.shouldShowActivityConfig).thenReturn(false)
-        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
-
-        var latest: Boolean? = null
-        val job = underTest
-                .isActivityInVisible
-                .onEach { latest = it }
-                .launchIn(this)
-
-        // Verify that on launch, we receive a false.
-        assertThat(latest).isFalse()
-
-        job.cancel()
-    }
-
-    @Test
-    fun activityInVisible_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
-        whenever(constants.shouldShowActivityConfig).thenReturn(false)
-        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
-
-        var latest: Boolean? = null
-        val job = underTest
-                .isActivityInVisible
-                .onEach { latest = it }
-                .launchIn(this)
-
-        // Update the repo to have activityIn
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+            WifiNetworkModel.Active(
+                NETWORK_ID,
+                isValidated = true,
+                level = 1
+            )
         )
         yield()
 
-        // Verify that we didn't update to activityIn=true (because our config is false)
-        assertThat(latest).isFalse()
+        assertThat(latestHome).isInstanceOf(Icon.Resource::class.java)
+        assertThat(latestHome).isEqualTo(latestKeyguard)
+        assertThat(latestKeyguard).isEqualTo(latestQs)
 
-        job.cancel()
+        jobHome.cancel()
+        jobKeyguard.cancel()
+        jobQs.cancel()
     }
 
     @Test
-    fun activityInVisible_showActivityConfigTrue_outputsUpdate() = runBlocking(IMMEDIATE) {
-        whenever(constants.shouldShowActivityConfig).thenReturn(true)
+    fun activity_showActivityConfigFalse_outputsFalse() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(false)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var activityIn: Boolean? = null
+        val activityInJob = underTest
+            .home
+            .isActivityInViewVisible
+            .onEach { activityIn = it }
+            .launchIn(this)
+
+        var activityOut: Boolean? = null
+        val activityOutJob = underTest
+            .home
+            .isActivityOutViewVisible
+            .onEach { activityOut = it }
+            .launchIn(this)
+
+        var activityContainer: Boolean? = null
+        val activityContainerJob = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { activityContainer = it }
+            .launchIn(this)
+
+        // Verify that on launch, we receive false.
+        assertThat(activityIn).isFalse()
+        assertThat(activityOut).isFalse()
+        assertThat(activityContainer).isFalse()
+
+        activityInJob.cancel()
+        activityOutJob.cancel()
+        activityContainerJob.cancel()
+    }
+
+    @Test
+    fun activity_showActivityConfigFalse_noUpdatesReceived() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(false)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var activityIn: Boolean? = null
+        val activityInJob = underTest
+            .home
+            .isActivityInViewVisible
+            .onEach { activityIn = it }
+            .launchIn(this)
+
+        var activityOut: Boolean? = null
+        val activityOutJob = underTest
+            .home
+            .isActivityOutViewVisible
+            .onEach { activityOut = it }
+            .launchIn(this)
+
+        var activityContainer: Boolean? = null
+        val activityContainerJob = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { activityContainer = it }
+            .launchIn(this)
+
+        // WHEN we update the repo to have activity
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        // THEN we didn't update to the new activity (because our config is false)
+        assertThat(activityIn).isFalse()
+        assertThat(activityOut).isFalse()
+        assertThat(activityContainer).isFalse()
+
+        activityInJob.cancel()
+        activityOutJob.cancel()
+        activityContainerJob.cancel()
+    }
+
+    @Test
+    fun activity_nullSsid_outputsFalse() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(NETWORK_ID, ssid = null))
+
+        var activityIn: Boolean? = null
+        val activityInJob = underTest
+            .home
+            .isActivityInViewVisible
+            .onEach { activityIn = it }
+            .launchIn(this)
+
+        var activityOut: Boolean? = null
+        val activityOutJob = underTest
+            .home
+            .isActivityOutViewVisible
+            .onEach { activityOut = it }
+            .launchIn(this)
+
+        var activityContainer: Boolean? = null
+        val activityContainerJob = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { activityContainer = it }
+            .launchIn(this)
+
+        // WHEN we update the repo to have activity
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        // THEN we still output false because our network's SSID is null
+        assertThat(activityIn).isFalse()
+        assertThat(activityOut).isFalse()
+        assertThat(activityContainer).isFalse()
+
+        activityInJob.cancel()
+        activityOutJob.cancel()
+        activityContainerJob.cancel()
+    }
+
+    @Test
+    fun activity_allLocationViewModelsReceiveSameData() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latestHome: Boolean? = null
+        val jobHome = underTest
+            .home
+            .isActivityInViewVisible
+            .onEach { latestHome = it }
+            .launchIn(this)
+
+        var latestKeyguard: Boolean? = null
+        val jobKeyguard = underTest
+            .keyguard
+            .isActivityInViewVisible
+            .onEach { latestKeyguard = it }
+            .launchIn(this)
+
+        var latestQs: Boolean? = null
+        val jobQs = underTest
+            .qs
+            .isActivityInViewVisible
+            .onEach { latestQs = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latestHome).isTrue()
+        assertThat(latestKeyguard).isTrue()
+        assertThat(latestQs).isTrue()
+
+        jobHome.cancel()
+        jobKeyguard.cancel()
+        jobQs.cancel()
+    }
+
+    @Test
+    fun activityIn_hasActivityInTrue_outputsTrue() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
         wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
 
         var latest: Boolean? = null
         val job = underTest
-                .isActivityInVisible
-                .onEach { latest = it }
-                .launchIn(this)
+            .home
+            .isActivityInViewVisible
+            .onEach { latest = it }
+            .launchIn(this)
 
-        // Update the repo to have activityIn
-        wifiRepository.setWifiActivity(
-            WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
-        )
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity)
         yield()
 
-        // Verify that we updated to activityIn=true
         assertThat(latest).isTrue()
 
         job.cancel()
     }
 
-    private fun ContentDescription.getAsString(): String? {
-        return when (this) {
-            is ContentDescription.Loaded -> this.description
-            is ContentDescription.Resource -> context.getString(this.res)
-        }
+    @Test
+    fun activityIn_hasActivityInFalse_outputsFalse() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityInViewVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isFalse()
+
+        job.cancel()
+    }
+
+    @Test
+    fun activityOut_hasActivityOutTrue_outputsTrue() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityOutViewVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isTrue()
+
+        job.cancel()
+    }
+
+    @Test
+    fun activityOut_hasActivityOutFalse_outputsFalse() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityOutViewVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isFalse()
+
+        job.cancel()
+    }
+
+    @Test
+    fun activityContainer_hasActivityInTrue_outputsTrue() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isTrue()
+
+        job.cancel()
+    }
+
+    @Test
+    fun activityContainer_hasActivityOutTrue_outputsTrue() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = false, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isTrue()
+
+        job.cancel()
+    }
+
+    @Test
+    fun activityContainer_inAndOutTrue_outputsTrue() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isTrue()
+
+        job.cancel()
+    }
+
+    @Test
+    fun activityContainer_inAndOutFalse_outputsFalse() = runBlocking(IMMEDIATE) {
+        whenever(wifiConstants.shouldShowActivityConfig).thenReturn(true)
+        createAndSetViewModel()
+        wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK)
+
+        var latest: Boolean? = null
+        val job = underTest
+            .home
+            .isActivityContainerVisible
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity)
+        yield()
+
+        assertThat(latest).isFalse()
+
+        job.cancel()
+    }
+
+    private fun createAndSetViewModel() {
+        // [WifiViewModel] creates its flows as soon as it's instantiated, and some of those flow
+        // creations rely on certain config values that we mock out in individual tests. This method
+        // allows tests to create the view model only after those configs are correctly set up.
+        underTest = WifiViewModel(
+            connectivityConstants,
+            context,
+            logger,
+            interactor,
+            scope,
+            statusBarPipelineFlags,
+            wifiConstants,
+        )
     }
 
     companion object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index c47ea9c..6ace404 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -275,10 +275,9 @@
         EditText editText = view.findViewById(R.id.remote_input_text);
         editText.setText(TEST_REPLY);
         ClipDescription description = new ClipDescription("", new String[] {"image/png"});
-        // We need to use an (arbitrary) real resource here so that an actual image gets attached.
+        // We need to use an (arbitrary) real resource here so that an actual image gets attached
         ClipData clip = new ClipData(description, new ClipData.Item(
-                Uri.parse("android.resource://com.android.systemui/"
-                        + R.drawable.default_thumbnail)));
+                Uri.parse("android.resource://android/" + android.R.drawable.btn_default)));
         ContentInfo payload =
                 new ContentInfo.Builder(clip, SOURCE_CLIPBOARD).build();
         view.setAttachment(payload);
diff --git a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
index ad09f7c..33f1b42 100644
--- a/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
+++ b/services/companion/java/com/android/server/companion/presence/BleCompanionDeviceScanner.java
@@ -184,13 +184,21 @@
     @MainThread
     private void startScan() {
         enforceInitialized();
-        // This method should not be called if scan is already in progress.
-        if (mScanning) throw new IllegalStateException("Scan is already in progress.");
-        // Neither should this method be called if the adapter is not available.
-        if (mBleScanner == null) throw new IllegalStateException("BLE is not available.");
 
         if (DEBUG) Log.i(TAG, "startScan()");
 
+        // This method should not be called if scan is already in progress.
+        if (mScanning) {
+            Slog.w(TAG, "Scan is already in progress.");
+            return;
+        }
+
+        // Neither should this method be called if the adapter is not available.
+        if (mBleScanner == null) {
+            Slog.w(TAG, "BLE is not available.");
+            return;
+        }
+
         // Collect MAC addresses from all associations.
         final Set<String> macAddresses = new HashSet<>();
         for (AssociationInfo association : mAssociationStore.getAssociations()) {
@@ -221,8 +229,18 @@
             filters.add(filter);
         }
 
-        mBleScanner.startScan(filters, SCAN_SETTINGS, mScanCallback);
-        mScanning = true;
+        // BluetoothLeScanner will throw an IllegalStateException if startScan() is called while LE
+        // is not enabled.
+        if (mBtAdapter.isLeEnabled()) {
+            try {
+                mBleScanner.startScan(filters, SCAN_SETTINGS, mScanCallback);
+                mScanning = true;
+            } catch (IllegalStateException e) {
+                Slog.w(TAG, "Exception while starting BLE scanning", e);
+            }
+        } else {
+            Slog.w(TAG, "BLE scanning is not turned on");
+        }
     }
 
     private void stopScanIfNeeded() {
@@ -240,11 +258,11 @@
         if (mBtAdapter.isLeEnabled()) {
             try {
                 mBleScanner.stopScan(mScanCallback);
-            } catch (RuntimeException e) {
-                // Just to be sure not to crash system server here if BluetoothLeScanner throws
-                // another RuntimeException.
+            } catch (IllegalStateException e) {
                 Slog.w(TAG, "Exception while stopping BLE scanning", e);
             }
+        } else {
+            Slog.w(TAG, "BLE scanning is not turned on");
         }
 
         mScanning = false;
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index efb2cb7..2a21928 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -411,8 +411,11 @@
 
             // For a new display, we need to initialize the default mode ID.
             if (mDefaultModeId == INVALID_MODE_ID) {
-                mDefaultModeId = activeRecord.mMode.getModeId();
-                mDefaultModeGroup = mActiveSfDisplayMode.group;
+                mDefaultModeId = mSystemPreferredModeId != INVALID_MODE_ID
+                        ? mSystemPreferredModeId : activeRecord.mMode.getModeId();
+                mDefaultModeGroup = mSystemPreferredModeId != INVALID_MODE_ID
+                        ? preferredSfDisplayMode.group
+                        : mActiveSfDisplayMode.group;
             } else if (modesAdded && activeModeChanged) {
                 Slog.d(TAG, "New display modes are added and the active mode has changed, "
                         + "use active mode as default mode.");
@@ -894,13 +897,6 @@
         public void setUserPreferredDisplayModeLocked(Display.Mode mode) {
             final int oldModeId = getPreferredModeId();
             mUserPreferredMode = mode;
-            // When clearing the user preferred mode we need to also reset the default mode. This is
-            // used by DisplayModeDirector to determine the default resolution, so if we don't clear
-            // it then the resolution won't reset to what it would've been prior to setting a user
-            // preferred display mode.
-            if (mode == null && mSystemPreferredModeId != INVALID_MODE_ID) {
-                mDefaultModeId = mSystemPreferredModeId;
-            }
             if (mode != null && (mode.isRefreshRateSet() || mode.isResolutionSet())) {
                 Display.Mode matchingSupportedMode;
                 matchingSupportedMode = findMode(mode.getPhysicalWidth(),
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 5599f2c..9c95e31 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -1032,8 +1032,12 @@
     private void applyAnimations(ArraySet<ActivityRecord> openingApps,
             ArraySet<ActivityRecord> closingApps, @TransitionOldType int transit,
             LayoutParams animLp, boolean voiceInteraction) {
+        final RecentsAnimationController rac = mService.getRecentsAnimationController();
         if (transit == WindowManager.TRANSIT_OLD_UNSET
                 || (openingApps.isEmpty() && closingApps.isEmpty())) {
+            if (rac != null) {
+                rac.sendTasksAppeared();
+            }
             return;
         }
 
@@ -1071,7 +1075,6 @@
                 voiceInteraction);
         applyAnimations(closingWcs, closingApps, transit, false /* visible */, animLp,
                 voiceInteraction);
-        final RecentsAnimationController rac = mService.getRecentsAnimationController();
         if (rac != null) {
             rac.sendTasksAppeared();
         }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 95d71a3..71c80fb 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -6729,4 +6729,11 @@
     DisplayContent asDisplayContent() {
         return this;
     }
+
+    @Override
+    @Surface.Rotation
+    int getRelativeDisplayRotation() {
+        // Display is the root, so it's not rotated relative to anything.
+        return Surface.ROTATION_0;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index b26de07..4c69f87 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2168,10 +2168,7 @@
      * If the decor insets changes, the display configuration may be affected. The caller should
      * call {@link DisplayContent#sendNewConfiguration()} if this method returns {@code true}.
      */
-    boolean updateDecorInsetsInfoIfNeeded(WindowState win) {
-        if (!win.providesNonDecorInsets()) {
-            return false;
-        }
+    boolean updateDecorInsetsInfo() {
         final DisplayFrames displayFrames = mDisplayContent.mDisplayFrames;
         final int rotation = displayFrames.mRotation;
         final int dw = displayFrames.mWidth;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 383fcb9..07ae167 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -477,7 +477,10 @@
             }
             mLocalInsetsSourceProviders.remove(insetsTypes[i]);
         }
-        mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
+        // Update insets if this window is attached.
+        if (mDisplayContent != null) {
+            mDisplayContent.getInsetsStateController().updateAboveInsetsState(true);
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c96253c..4d37e08 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1858,8 +1858,12 @@
             ProtoLog.v(WM_DEBUG_ADD_REMOVE, "addWindow: New client %s"
                     + ": window=%s Callers=%s", client.asBinder(), win, Debug.getCallers(5));
 
-            if ((win.isVisibleRequestedOrAdding() && displayContent.updateOrientation())
-                    || displayPolicy.updateDecorInsetsInfoIfNeeded(win)) {
+            boolean needToSendNewConfiguration =
+                    win.isVisibleRequestedOrAdding() && displayContent.updateOrientation();
+            if (win.providesNonDecorInsets()) {
+                needToSendNewConfiguration |= displayPolicy.updateDecorInsetsInfo();
+            }
+            if (needToSendNewConfiguration) {
                 displayContent.sendNewConfiguration();
             }
 
@@ -2329,8 +2333,8 @@
                         & WindowManager.LayoutParams.SYSTEM_UI_VISIBILITY_CHANGED) != 0) {
                     win.mLayoutNeeded = true;
                 }
-                if (layoutChanged) {
-                    configChanged = displayPolicy.updateDecorInsetsInfoIfNeeded(win);
+                if (layoutChanged && win.providesNonDecorInsets()) {
+                    configChanged = displayPolicy.updateDecorInsetsInfo();
                 }
                 if (win.mActivityRecord != null && ((flagChanges & FLAG_SHOW_WHEN_LOCKED) != 0
                         || (flagChanges & FLAG_DISMISS_KEYGUARD) != 0)) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 7c9d277..42d2861 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2627,11 +2627,19 @@
                 }
             }
 
+            // Check if window provides non decor insets before clearing its provided insets.
+            final boolean windowProvidesNonDecorInsets = providesNonDecorInsets();
+
             removeImmediately();
             // Removing a visible window may affect the display orientation so just update it if
             // needed. Also recompute configuration if it provides screen decor insets.
-            if ((wasVisible && displayContent.updateOrientation())
-                    || displayContent.getDisplayPolicy().updateDecorInsetsInfoIfNeeded(this)) {
+            boolean needToSendNewConfiguration = wasVisible && displayContent.updateOrientation();
+            if (windowProvidesNonDecorInsets) {
+                needToSendNewConfiguration |=
+                        displayContent.getDisplayPolicy().updateDecorInsetsInfo();
+            }
+
+            if (needToSendNewConfiguration) {
                 displayContent.sendNewConfiguration();
             }
             mWmService.updateFocusedWindowLocked(isFocused()
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index ed369c0..9c615d1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -764,13 +764,11 @@
     @Test
     public void testGetSystemPreferredDisplayMode() throws Exception {
         SurfaceControl.DisplayMode displayMode1 = createFakeDisplayMode(0, 1920, 1080, 60f);
-        // system preferred mode
+        // preferred mode
         SurfaceControl.DisplayMode displayMode2 = createFakeDisplayMode(1, 3840, 2160, 60f);
-        // user preferred mode
-        SurfaceControl.DisplayMode displayMode3 = createFakeDisplayMode(2, 1920, 1080, 30f);
 
         SurfaceControl.DisplayMode[] modes =
-                new SurfaceControl.DisplayMode[]{displayMode1, displayMode2, displayMode3};
+                new SurfaceControl.DisplayMode[]{displayMode1, displayMode2};
         FakeDisplay display = new FakeDisplay(PORT_A, modes, 0, 1);
         setUpDisplay(display);
         updateAvailableDisplays();
@@ -782,43 +780,24 @@
 
         DisplayDeviceInfo displayDeviceInfo = mListener.addedDisplays.get(
                 0).getDisplayDeviceInfoLocked();
+
         assertThat(displayDeviceInfo.supportedModes.length).isEqualTo(modes.length);
+
         Display.Mode defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId);
-        assertThat(matches(defaultMode, displayMode1)).isTrue();
-
-        // Set the user preferred display mode
-        mListener.addedDisplays.get(0).setUserPreferredDisplayModeLocked(
-                new Display.Mode(
-                        displayMode3.width, displayMode3.height, displayMode3.refreshRate));
-        updateAvailableDisplays();
-        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
-        displayDeviceInfo = mListener.addedDisplays.get(
-                0).getDisplayDeviceInfoLocked();
-        defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId);
-        assertThat(matches(defaultMode, displayMode3)).isTrue();
-
-        // clear the user preferred mode
-        mListener.addedDisplays.get(0).setUserPreferredDisplayModeLocked(null);
-        updateAvailableDisplays();
-        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
-        displayDeviceInfo = mListener.addedDisplays.get(
-                0).getDisplayDeviceInfoLocked();
-        defaultMode = getModeById(displayDeviceInfo, displayDeviceInfo.defaultModeId);
         assertThat(matches(defaultMode, displayMode2)).isTrue();
 
-        // Change the display and add new system preferred mode
-        SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(3, 2340, 1080, 20f);
-        modes = new SurfaceControl.DisplayMode[]{
-                displayMode1, displayMode2, displayMode3, addedDisplayInfo};
+        // Change the display and add new preferred mode
+        SurfaceControl.DisplayMode addedDisplayInfo = createFakeDisplayMode(2, 2340, 1080, 60f);
+        modes = new SurfaceControl.DisplayMode[]{displayMode1, displayMode2, addedDisplayInfo};
         display.dynamicInfo.supportedDisplayModes = modes;
-        display.dynamicInfo.preferredBootDisplayMode = 3;
+        display.dynamicInfo.preferredBootDisplayMode = 2;
         setUpDisplay(display);
         mInjector.getTransmitter().sendHotplug(display, /* connected */ true);
         waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
 
         assertTrue(mListener.traversalRequested);
         assertThat(mListener.addedDisplays.size()).isEqualTo(1);
-        assertThat(mListener.changedDisplays.size()).isEqualTo(3);
+        assertThat(mListener.changedDisplays.size()).isEqualTo(1);
 
         DisplayDevice displayDevice = mListener.changedDisplays.get(0);
         displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 95e9f20..d544744 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2992,7 +2992,8 @@
                 .setSystemDecorations(true).build();
         // Add a decor insets provider window.
         final WindowState navbar = createNavBarWithProvidedInsets(squareDisplay);
-        squareDisplay.getDisplayPolicy().updateDecorInsetsInfoIfNeeded(navbar);
+        assertTrue(navbar.providesNonDecorInsets()
+                && squareDisplay.getDisplayPolicy().updateDecorInsetsInfo());
         squareDisplay.sendNewConfiguration();
         final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build();
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index e00296f..73eb127 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -292,12 +292,16 @@
         final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
         final DisplayInfo di = mDisplayContent.getDisplayInfo();
         final int prevScreenHeightDp = mDisplayContent.getConfiguration().screenHeightDp;
-        assertTrue(displayPolicy.updateDecorInsetsInfoIfNeeded(navbar));
+        assertTrue(navbar.providesNonDecorInsets() && displayPolicy.updateDecorInsetsInfo());
         assertEquals(NAV_BAR_HEIGHT, displayPolicy.getDecorInsetsInfo(di.rotation,
                 di.logicalWidth, di.logicalHeight).mConfigInsets.bottom);
         mDisplayContent.sendNewConfiguration();
         assertNotEquals(prevScreenHeightDp, mDisplayContent.getConfiguration().screenHeightDp);
-        assertFalse(displayPolicy.updateDecorInsetsInfoIfNeeded(navbar));
+        assertFalse(navbar.providesNonDecorInsets() && displayPolicy.updateDecorInsetsInfo());
+
+        navbar.removeIfPossible();
+        assertEquals(0, displayPolicy.getDecorInsetsInfo(di.rotation, di.logicalWidth,
+                di.logicalHeight).mNonDecorInsets.bottom);
     }
 
     @UseTestDisplay(addWindows = { W_NAVIGATION_BAR, W_INPUT_METHOD })
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 7eec86a..0fdf40d 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -23,6 +23,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Locale;
 
 /**
  * Contains access network related constants.
@@ -114,7 +115,7 @@
 
         /** @hide */
         public static @RadioAccessNetworkType int fromString(@NonNull String str) {
-            switch (str.toUpperCase()) {
+            switch (str.toUpperCase(Locale.ROOT)) {
                 case "UNKNOWN": return UNKNOWN;
                 case "GERAN": return GERAN;
                 case "UTRAN": return UTRAN;