Merge "Fix issues in RTL." into rvc-dev
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index bd811fc..a954f36 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1200,8 +1200,10 @@
         }
 
         if (mDeferredDestroySurfaceControl != null) {
-            mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply();
-            mDeferredDestroySurfaceControl = null;
+            synchronized (mSurfaceControlLock) {
+                mTmpTransaction.remove(mDeferredDestroySurfaceControl).apply();
+                mDeferredDestroySurfaceControl = null;
+            }
         }
 
         runOnUiThread(this::performDrawFinished);
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index b387a68..68943bf 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -75,7 +75,10 @@
     /** @hide */
     public static AutofillId withoutSession(@NonNull AutofillId id) {
         final int flags = id.mFlags & ~FLAG_HAS_SESSION;
-        return new AutofillId(flags, id.mViewId, id.mVirtualLongId, NO_SESSION);
+        final long virtualChildId =
+                ((id.mFlags & FLAG_IS_VIRTUAL_LONG) != 0) ? id.mVirtualLongId
+                        : id.mVirtualIntId;
+        return new AutofillId(flags, id.mViewId, virtualChildId, NO_SESSION);
     }
 
     /** @hide */
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 65872f4..afeceb7 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1309,7 +1309,7 @@
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Εντοπίστηκε αναλογικό αξεσουάρ ήχου"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Η συνδεδεμένη συσκευή δεν είναι συμβατή με αυτό το τηλέφωνο. Πατήστε για να μάθετε περισσότερα."</string>
     <string name="adb_active_notification_title" msgid="408390247354560331">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string>
-    <string name="adb_active_notification_message" msgid="5617264033476778211">"Απενεργοποιήστε τον εντοπισμό/διόρθ. σφαλμάτων USB"</string>
+    <string name="adb_active_notification_message" msgid="5617264033476778211">"Πατήστε για απενεργοποίηση εντοπισμού/διόρθ. σφαλμάτων USB"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Επιλογή για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Συνδέθηκε ο ασύρματος εντοπισμός σφαλμάτων"</string>
     <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Πατήστε, για να απενεργοποιήσετε τον ασύρματο εντοπισμό σφαλμάτων"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 36380b8..31abd82 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -202,10 +202,8 @@
     <string name="printing_disabled_by" msgid="3517499806528864633">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‎‎‎‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‎‎‎‎‎‏‎‏‏‏‏‎‎‏‎Printing disabled by ‎‏‎‎‏‏‎<xliff:g id="OWNER_APP">%s</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎"</string>
     <string name="personal_apps_suspension_title" msgid="7561416677884286600">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‏‎‎‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‏‎‎‎‏‎‎‎‎Turn on your work profile‎‏‎‎‏‎"</string>
     <string name="personal_apps_suspension_text" msgid="6115455688932935597">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‏‏‎‏‎Your personal apps are blocked until you turn on your work profile‎‏‎‎‏‎"</string>
-    <!-- no translation found for personal_apps_suspension_soon_text (8123898693479590) -->
-    <skip />
-    <!-- no translation found for personal_apps_suspended_turn_profile_on (2758012869627513689) -->
-    <skip />
+    <string name="personal_apps_suspension_soon_text" msgid="8123898693479590">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‎‎‏‎‏‎‎‏‏‎‎Personal apps will be blocked on ‎‏‎‎‏‏‎<xliff:g id="DATE">%1$s</xliff:g>‎‏‎‎‏‏‏‎ at ‎‏‎‎‏‏‎<xliff:g id="TIME">%2$s</xliff:g>‎‏‎‎‏‏‏‎. Your IT admin doesn’t allow your work profile to stay off for more than ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%3$d</xliff:g>‎‏‎‎‏‏‏‎ days.‎‏‎‎‏‎"</string>
+    <string name="personal_apps_suspended_turn_profile_on" msgid="2758012869627513689">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‎‎‏‎‎‎‏‏‎‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‎‎‎‎‏‏‎‏‎‏‎‎‎‏‎‏‏‎‏‎‏‏‎‎‏‎Turn on‎‏‎‎‏‎"</string>
     <string name="me" msgid="6207584824693813140">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‏‎‏‎‏‏‏‎‏‏‏‏‏‎‎‏‎‏‎‎‎Me‎‏‎‎‏‎"</string>
     <string name="power_dialog" product="tablet" msgid="8333207765671417261">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎Tablet options‎‏‎‎‏‎"</string>
     <string name="power_dialog" product="tv" msgid="7792839006640933763">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‏‎‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‏‎Android TV options‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 91a8d05..bb06173 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -2032,7 +2032,7 @@
       <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ficheiros</item>
       <item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> ficheiro</item>
     </plurals>
-    <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Non hai persoas recomendadas coas que compartir contido"</string>
+    <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"Non hai recomendacións de persoas coas que compartir contido"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"Lista de aplicacións"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"Esta aplicación non está autorizada a realizar gravacións, pero pode capturar audio a través deste dispositivo USB."</string>
     <string name="accessibility_system_action_home_label" msgid="3234748160850301870">"Inicio"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 3fe0766..5161fdc 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1230,7 +1230,7 @@
     <string name="volume_unknown" msgid="4041914008166576293">"កម្រិត​សំឡេង"</string>
     <string name="volume_icon_description_bluetooth" msgid="7540388479345558400">"កម្រិត​សំឡេង​ប៊្លូធូស"</string>
     <string name="volume_icon_description_ringer" msgid="2187800636867423459">"កម្រិត​សំឡេង​រោទ៍"</string>
-    <string name="volume_icon_description_incall" msgid="4491255105381227919">"កម្រិត​សំឡេង​ហៅ"</string>
+    <string name="volume_icon_description_incall" msgid="4491255105381227919">"កម្រិត​សំឡេង​ហៅទូរសព្ទ"</string>
     <string name="volume_icon_description_media" msgid="4997633254078171233">"កម្រិត​សំឡេង​មេឌៀ"</string>
     <string name="volume_icon_description_notification" msgid="579091344110747279">"កម្រិត​សំឡេង​ការ​ជូន​ដំណឹង"</string>
     <string name="ringtone_default" msgid="9118299121288174597">"សំឡេង​រោទ៍​លំនាំដើម"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index bc896d6..25aa3b5 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1308,7 +1308,7 @@
     <string name="usb_power_notification_message" msgid="7284765627437897702">"ಸಂಪರ್ಕಗೊಂಡಿರುವ ಸಾಧನವನ್ನು ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ. ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"ಅನ್‌ಲಾಗ್ ಆಡಿಯೋ ಪರಿಕರ ಪತ್ತೆಯಾಗಿದೆ"</string>
     <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"ಲಗತ್ತಿಸಲಾದ ಸಾಧನವು ಈ ಫೋನಿನೊಂದಿಗೆ ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ. ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
-    <string name="adb_active_notification_title" msgid="408390247354560331">"USB ಡೀಬಗಿಂಗ್‌‌ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+    <string name="adb_active_notification_title" msgid="408390247354560331">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
     <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ಆಫ್‌ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ"</string>
     <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಆಯ್ಕೆ ಮಾಡಿ."</string>
     <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ವೈರ್‌ಲೆಸ್ ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲಾಗಿದೆ"</string>
@@ -2032,7 +2032,7 @@
       <item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ಫೈಲ್‌ಗಳು</item>
       <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ಫೈಲ್‌ಗಳು</item>
     </plurals>
-    <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"ಹಂಚಿಕೊಳ್ಳಲು, ಯಾವುದೇ ಶಿಫಾರಸು ಮಾಡಲಾದ ಜನರಿಲ್ಲ"</string>
+    <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"ಹಂಚಿಕೊಳ್ಳಲು ಶಿಫಾರಸು ಮಾಡಲಾದವರು ಯಾರೂ ಇಲ್ಲ"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"ಆ್ಯಪ್‌ಗಳ ಪಟ್ಟಿ"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"ಈ ಆ್ಯಪ್‌ಗೆ ರೆಕಾರ್ಡ್ ಅನುಮತಿಯನ್ನು ನೀಡಲಾಗಿಲ್ಲ, ಆದರೆ ಈ USB ಸಾಧನದ ಮೂಲಕ ಆಡಿಯೊವನ್ನು ಸೆರೆಹಿಡಿಯಬಲ್ಲದು."</string>
     <string name="accessibility_system_action_home_label" msgid="3234748160850301870">"ಹೋಮ್"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index a7e6f99..a5a0f9e 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -2032,7 +2032,7 @@
       <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> फाइल</item>
       <item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> फाइल</item>
     </plurals>
-    <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"शेअर करण्यासाठी कोणतीही शिफारस केलेले लोक नाहीत"</string>
+    <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"शेअर करण्यासाठी शिफारस केलेल्या कोणत्याही व्यक्ती नाहीत"</string>
     <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"अ‍ॅप्स सूची"</string>
     <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"या अ‍ॅपला रेकॉर्ड करण्याची परवानगी दिली गेली नाही पण हे USB डिव्हाइस वापरून ऑडिओ कॅप्चर केला जाऊ शकतो."</string>
     <string name="accessibility_system_action_home_label" msgid="3234748160850301870">"होम"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index cc8137c..64302da 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1912,7 +1912,7 @@
     <string name="demo_starting_message" msgid="6577581216125805905">"Demo starten…"</string>
     <string name="demo_restarting_message" msgid="1160053183701746766">"Apparaat resetten…"</string>
     <string name="suspended_widget_accessibility" msgid="6331451091851326101">"<xliff:g id="LABEL">%1$s</xliff:g> uitgeschakeld"</string>
-    <string name="conference_call" msgid="5731633152336490471">"Telefonische vergadering"</string>
+    <string name="conference_call" msgid="5731633152336490471">"Conferencecall"</string>
     <string name="tooltip_popup_title" msgid="7863719020269945722">"Knopinfo"</string>
     <string name="app_category_game" msgid="4534216074910244790">"Games"</string>
     <string name="app_category_audio" msgid="8296029904794676222">"Muziek en audio"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index f803f02..4becdaa 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -60,7 +60,7 @@
     <string name="ClirMmi" msgid="4702929460236547156">"ଆଉଟଗୋଇଙ୍ଗ୍ କଲର୍ ଆଇଡି"</string>
     <string name="ColpMmi" msgid="4736462893284419302">"ସଂଯୁକ୍ତ ଲାଇନ୍ ID"</string>
     <string name="ColrMmi" msgid="5889782479745764278">"ସଂଯୁକ୍ତ ଲାଇନ୍ ID କଟକଣା"</string>
-    <string name="CfMmi" msgid="8390012691099787178">"କଲ୍‌ ଫରୱାର୍ଡିଙ୍ଗ"</string>
+    <string name="CfMmi" msgid="8390012691099787178">"କଲ୍‌ ଫରୱାର୍ଡିଂ"</string>
     <string name="CwMmi" msgid="3164609577675404761">"କଲ୍‌ ଅପେକ୍ଷାରତ"</string>
     <string name="BaMmi" msgid="7205614070543372167">"କଲ୍‌ ବ୍ୟାରିଙ୍ଗ୍"</string>
     <string name="PwdMmi" msgid="3360991257288638281">"ପାସ୍‌ୱର୍ଡ ପରିବର୍ତ୍ତନ"</string>
@@ -88,7 +88,7 @@
     <string name="EmergencyCallWarningTitle" msgid="1615688002899152860">"ଜରୁରୀକାଳୀନ କଲ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
     <string name="EmergencyCallWarningSummary" msgid="1194185880092805497">"ୱାଇ-ଫାଇ ସାହାଯ୍ୟରେ ଜରୁରୀକାଳୀନ କଲ୍ କରାଯାଇପାରିବ ନାହିଁ"</string>
     <string name="notification_channel_network_alert" msgid="4788053066033851841">"ଆଲର୍ଟ"</string>
-    <string name="notification_channel_call_forward" msgid="8230490317314272406">"କଲ୍‌ ଫରୱାର୍ଡିଙ୍ଗ"</string>
+    <string name="notification_channel_call_forward" msgid="8230490317314272406">"କଲ୍‌ ଫରୱାର୍ଡିଂ"</string>
     <string name="notification_channel_emergency_callback" msgid="54074839059123159">"ଜରୁରୀକାଳୀନ କଲବ୍ୟାକ୍‍ ମୋଡ୍‍"</string>
     <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"ମୋବାଇଲ୍‍ ଡାଟା ଷ୍ଟାଟସ୍‌"</string>
     <string name="notification_channel_sms" msgid="1243384981025535724">"SMS ମେସେଜ୍‌"</string>
diff --git a/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java b/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
index a8ca6f0..b329e55 100644
--- a/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
+++ b/core/tests/coretests/src/android/view/autofill/AutofillIdTest.java
@@ -126,6 +126,32 @@
     }
 
     @Test
+    public void testVirtual_Long_withoutSession() {
+        final AutofillId id = new AutofillId(new AutofillId(42), 108L, 666);
+        final AutofillId idWithoutSession = AutofillId.withoutSession(id);
+        assertThat(idWithoutSession.getViewId()).isEqualTo(42);
+        assertThat(idWithoutSession.isVirtualLong()).isTrue();
+        assertThat(idWithoutSession.isVirtualInt()).isFalse();
+        assertThat(idWithoutSession.isNonVirtual()).isFalse();
+        assertThat(idWithoutSession.getVirtualChildLongId()).isEqualTo(108L);
+        assertThat(idWithoutSession.getVirtualChildIntId()).isEqualTo(View.NO_ID);
+        assertThat(idWithoutSession.getSessionId()).isEqualTo(NO_SESSION);
+    }
+
+    @Test
+    public void testVirtual_Int_withoutSession() {
+        final AutofillId id = new AutofillId(42, 108);
+        final AutofillId idWithoutSession = AutofillId.withoutSession(id);
+        assertThat(idWithoutSession.getViewId()).isEqualTo(42);
+        assertThat(idWithoutSession.isVirtualLong()).isFalse();
+        assertThat(idWithoutSession.isVirtualInt()).isTrue();
+        assertThat(idWithoutSession.isNonVirtual()).isFalse();
+        assertThat(idWithoutSession.getVirtualChildIntId()).isEqualTo(108);
+        assertThat(idWithoutSession.getVirtualChildLongId()).isEqualTo(View.NO_ID);
+        assertThat(idWithoutSession.getSessionId()).isEqualTo(NO_SESSION);
+    }
+
+    @Test
     public void testSetResetSession() {
         final AutofillId id = new AutofillId(42);
         assertNonVirtual(id, 42, NO_SESSION);
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 10e9137..2a40b76 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -58,16 +58,14 @@
 
     override fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) {
         bouncerOrRun {
-            val effect = if (!isChecked) Vibrations.toggleOnEffect else Vibrations.toggleOffEffect
-            vibrate(effect)
+            cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
             cvh.action(BooleanAction(templateId, !isChecked))
         }
     }
 
     override fun touch(cvh: ControlViewHolder, templateId: String, control: Control) {
-        vibrate(Vibrations.toggleOnEffect)
-
         bouncerOrRun {
+            cvh.layout.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK)
             if (cvh.usePanel()) {
                 showDialog(cvh, control.getAppIntent().getIntent())
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
index 1f0ca9b..0ec4cc5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ToggleRangeBehavior.kt
@@ -231,9 +231,11 @@
 
         rangeAnimator?.cancel()
         if (isDragging) {
-            clipLayer.level = newLevel
             val isEdge = newLevel == MIN_LEVEL || newLevel == MAX_LEVEL
-            cvh.controlActionCoordinator.drag(isEdge)
+            if (clipLayer.level != newLevel) {
+                cvh.controlActionCoordinator.drag(isEdge)
+                clipLayer.level = newLevel
+            }
         } else if (newLevel != clipLayer.level) {
             rangeAnimator = ValueAnimator.ofInt(cvh.clipLayer.level, newLevel).apply {
                 addUpdateListener {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt
index c0f6aab..29b7e985 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/Vibrations.kt
@@ -20,35 +20,9 @@
 import android.os.VibrationEffect.Composition.PRIMITIVE_TICK
 
 object Vibrations {
-    private const val TOGGLE_TICK_COUNT = 40
-
-    val toggleOnEffect = initToggleOnEffect()
-    val toggleOffEffect = initToggleOffEffect()
     val rangeEdgeEffect = initRangeEdgeEffect()
     val rangeMiddleEffect = initRangeMiddleEffect()
 
-    private fun initToggleOnEffect(): VibrationEffect {
-        val composition = VibrationEffect.startComposition()
-        composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 200)
-        var i = 0
-        while (i++ < TOGGLE_TICK_COUNT) {
-            composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 0)
-        }
-        composition.addPrimitive(PRIMITIVE_TICK, 0.5f, 100)
-        return composition.compose()
-    }
-
-    private fun initToggleOffEffect(): VibrationEffect {
-        val composition = VibrationEffect.startComposition()
-        composition.addPrimitive(PRIMITIVE_TICK, 0.5f, 0)
-        composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 100)
-        var i = 0
-        while (i++ < TOGGLE_TICK_COUNT) {
-            composition.addPrimitive(PRIMITIVE_TICK, 0.05f, 0)
-        }
-        return composition.compose()
-    }
-
     private fun initRangeEdgeEffect(): VibrationEffect {
         val composition = VibrationEffect.startComposition()
         composition.addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 0.5f)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java
index 9dcc187..87612f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java
@@ -52,7 +52,7 @@
     private NotificationGuts mGutsContainer;
 
     private OnClickListener mOnOk = v -> {
-        closeControls(v);
+        mGutsContainer.closeControls(v, false);
     };
 
     public AppOpsInfo(Context context, AttributeSet attrs) {
@@ -117,6 +117,7 @@
         });
         TextView ok = findViewById(R.id.ok);
         ok.setOnClickListener(mOnOk);
+        ok.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
     }
 
     private String getPrompt() {
@@ -160,19 +161,6 @@
         }
     }
 
-    private void closeControls(View v) {
-        mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
-        int[] parentLoc = new int[2];
-        int[] targetLoc = new int[2];
-        mGutsContainer.getLocationOnScreen(parentLoc);
-        v.getLocationOnScreen(targetLoc);
-        final int centerX = v.getWidth() / 2;
-        final int centerY = v.getHeight() / 2;
-        final int x = targetLoc[0] - parentLoc[0] + centerX;
-        final int y = targetLoc[1] - parentLoc[1] + centerY;
-        mGutsContainer.closeControls(x, y, false, false);
-    }
-
     @Override
     public void setGutsParent(NotificationGuts guts) {
         mGutsContainer = guts;
@@ -200,6 +188,7 @@
 
     @Override
     public boolean handleCloseControls(boolean save, boolean force) {
+        mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false);
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index f7ad50e..94e12e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -1122,9 +1122,8 @@
     }
 
     public void setGutsView(MenuItem item) {
-        if (mGuts != null && item.getGutsView() instanceof NotificationGuts.GutsContent) {
-            ((NotificationGuts.GutsContent) item.getGutsView()).setGutsParent(mGuts);
-            mGuts.setGutsContent((NotificationGuts.GutsContent) item.getGutsView());
+        if (getGuts() != null && item.getGutsView() instanceof NotificationGuts.GutsContent) {
+            getGuts().setGutsContent((NotificationGuts.GutsContent) item.getGutsView());
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 2e7b175..daa4ffe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -137,13 +137,13 @@
         mSelectedAction = ACTION_HOME;
         mShortcutManager.requestPinShortcut(mShortcutInfo, null);
         mShadeController.animateCollapsePanels();
-        closeControls(v, true);
+        mGutsContainer.closeControls(v, true);
     };
 
     private OnClickListener mOnSnoozeClick = v -> {
         mSelectedAction = ACTION_SNOOZE;
         mOnSnoozeClickListener.onClick(v, 1);
-        closeControls(v, true);
+        mGutsContainer.closeControls(v, true);
     };
     */
 
@@ -164,7 +164,7 @@
 
     private OnClickListener mOnDone = v -> {
         mPressedApply = true;
-        closeControls(v, true);
+        mGutsContainer.closeControls(v, true);
     };
 
     public NotificationConversationInfo(Context context, AttributeSet attrs) {
@@ -258,6 +258,7 @@
 
         View done = findViewById(R.id.done);
         done.setOnClickListener(mOnDone);
+        done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
     }
 
     private void bindActions() {
@@ -543,25 +544,6 @@
         controller.show();
     }
 
-    /**
-     * Closes the controls and commits the updated importance values (indirectly).
-     *
-     * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
-     * user does not have the ability to undo the action anymore.
-     */
-    @VisibleForTesting
-    void closeControls(View v, boolean save) {
-        int[] parentLoc = new int[2];
-        int[] targetLoc = new int[2];
-        mGutsContainer.getLocationOnScreen(parentLoc);
-        v.getLocationOnScreen(targetLoc);
-        final int centerX = v.getWidth() / 2;
-        final int centerY = v.getHeight() / 2;
-        final int x = targetLoc[0] - parentLoc[0] + centerX;
-        final int y = targetLoc[1] - parentLoc[1] + centerY;
-        mGutsContainer.closeControls(x, y, save, false /* force */);
-    }
-
     @Override
     public void setGutsParent(NotificationGuts guts) {
         mGutsContainer = guts;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
index c762b73..eeac46a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java
@@ -22,12 +22,14 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
+import android.os.Bundle;
 import android.os.Handler;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
 import android.view.ViewAnimationUtils;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
 
 import androidx.annotation.Nullable;
@@ -59,6 +61,31 @@
 
     private GutsContent mGutsContent;
 
+    private View.AccessibilityDelegate mGutsContentAccessibilityDelegate =
+            new View.AccessibilityDelegate() {
+                @Override
+                public void onInitializeAccessibilityNodeInfo(
+                        View host, AccessibilityNodeInfo info) {
+                    super.onInitializeAccessibilityNodeInfo(host, info);
+                    info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_LONG_CLICK);
+                }
+
+                @Override
+                public boolean performAccessibilityAction(View host, int action, Bundle args) {
+                    if (super.performAccessibilityAction(host, action, args)) {
+                        return true;
+                    }
+
+                    switch (action) {
+                        case AccessibilityNodeInfo.ACTION_LONG_CLICK:
+                            closeControls(host, false);
+                            return true;
+                    }
+
+                    return false;
+                }
+            };
+
     public interface GutsContent {
 
         public void setGutsParent(NotificationGuts listener);
@@ -110,6 +137,11 @@
          * view on the lockscreen
          */
         boolean needsFalsingProtection();
+
+        /**
+         * Equivalent to {@link View#setAccessibilityDelegate(AccessibilityDelegate)}
+         */
+        void setAccessibilityDelegate(AccessibilityDelegate gutsContentAccessibilityDelegate);
     }
 
     public interface OnGutsClosedListener {
@@ -146,6 +178,8 @@
     }
 
     public void setGutsContent(GutsContent content) {
+        content.setGutsParent(this);
+        content.setAccessibilityDelegate(mGutsContentAccessibilityDelegate);
         mGutsContent = content;
         removeAllViews();
         addView(mGutsContent.getContentView());
@@ -237,13 +271,29 @@
 
     /**
      * Closes any exposed guts/views.
+     */
+    public void closeControls(View eventSource, boolean save) {
+        int[] parentLoc = new int[2];
+        int[] targetLoc = new int[2];
+        getLocationOnScreen(parentLoc);
+        eventSource.getLocationOnScreen(targetLoc);
+        final int centerX = eventSource.getWidth() / 2;
+        final int centerY = eventSource.getHeight() / 2;
+        final int x = targetLoc[0] - parentLoc[0] + centerX;
+        final int y = targetLoc[1] - parentLoc[1] + centerY;
+
+        closeControls(x, y, save, false);
+    }
+
+    /**
+     * Closes any exposed guts/views.
      *
      * @param x x coordinate to animate the close circular reveal with
      * @param y y coordinate to animate the close circular reveal with
      * @param save whether the state should be saved
      * @param force whether the guts should be force-closed regardless of state.
      */
-    public void closeControls(int x, int y, boolean save, boolean force) {
+    private void closeControls(int x, int y, boolean save, boolean force) {
         // First try to dismiss any blocking helper.
         boolean wasBlockingHelperDismissed =
                 Dependency.get(NotificationBlockingHelperManager.class)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index f434fbb..a131ebe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -141,7 +141,7 @@
     // used by standard ui
     private OnClickListener mOnDismissSettings = v -> {
         mPressedApply = true;
-        closeControls(v, true);
+        mGutsContainer.closeControls(v, true);
     };
 
     public NotificationInfo(Context context, AttributeSet attrs) {
@@ -250,7 +250,7 @@
 
         View done = findViewById(R.id.done);
         done.setOnClickListener(mOnDismissSettings);
-
+        done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
 
         View silent = findViewById(R.id.silence);
         View alert = findViewById(R.id.alert);
@@ -330,7 +330,7 @@
                         mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
                 mChannelEditorDialogController.setOnFinishListener(() -> {
                     mPresentingChannelEditorDialog = false;
-                    closeControls(this, false);
+                    mGutsContainer.closeControls(this, false);
                 });
                 mChannelEditorDialogController.show();
             }
@@ -528,25 +528,6 @@
         return intent;
     }
 
-    /**
-     * Closes the controls and commits the updated importance values (indirectly).
-     *
-     * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
-     * user does not have the ability to undo the action anymore.
-     */
-    @VisibleForTesting
-    void closeControls(View v, boolean save) {
-        int[] parentLoc = new int[2];
-        int[] targetLoc = new int[2];
-        mGutsContainer.getLocationOnScreen(parentLoc);
-        v.getLocationOnScreen(targetLoc);
-        final int centerX = v.getWidth() / 2;
-        final int centerY = v.getHeight() / 2;
-        final int x = targetLoc[0] - parentLoc[0] + centerX;
-        final int y = targetLoc[1] - parentLoc[1] + centerY;
-        mGutsContainer.closeControls(x, y, save, false /* force */);
-    }
-
     @Override
     public void setGutsParent(NotificationGuts guts) {
         mGutsContainer = guts;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
index cde3dfd..1ffb244 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java
@@ -380,16 +380,8 @@
 
     private void undoSnooze(View v) {
         mSelectedOption = null;
-        int[] parentLoc = new int[2];
-        int[] targetLoc = new int[2];
-        mGutsContainer.getLocationOnScreen(parentLoc);
-        v.getLocationOnScreen(targetLoc);
-        final int centerX = v.getWidth() / 2;
-        final int centerY = v.getHeight() / 2;
-        final int x = targetLoc[0] - parentLoc[0] + centerX;
-        final int y = targetLoc[1] - parentLoc[1] + centerY;
         showSnoozeOptions(false);
-        mGutsContainer.closeControls(x, y, false /* save */, false /* force */);
+        mGutsContainer.closeControls(v, false);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
index eb28c58..84bc181 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java
@@ -89,7 +89,7 @@
 
     private OnClickListener mOnDone = v -> {
         mPressedApply = true;
-        closeControls(v, true);
+        mGutsContainer.closeControls(v, true);
     };
 
     public PartialConversationInfo(Context context, AttributeSet attrs) {
@@ -132,6 +132,7 @@
 
         View done = findViewById(R.id.done);
         done.setOnClickListener(mOnDone);
+        done.setAccessibilityDelegate(mGutsContainer.getAccessibilityDelegate());
     }
 
     private void bindActions() {
@@ -172,7 +173,7 @@
                         mUniqueChannelsInRow, mPkgIcon, mOnSettingsClickListener);
                 mChannelEditorDialogController.setOnFinishListener(() -> {
                     mPresentingChannelEditorDialog = false;
-                    closeControls(this, false);
+                    mGutsContainer.closeControls(this, false);
                 });
                 mChannelEditorDialogController.show();
             }
@@ -317,25 +318,6 @@
         }
     }
 
-    /**
-     * Closes the controls and commits the updated importance values (indirectly).
-     *
-     * <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
-     * user does not have the ability to undo the action anymore.
-     */
-    @VisibleForTesting
-    void closeControls(View v, boolean save) {
-        int[] parentLoc = new int[2];
-        int[] targetLoc = new int[2];
-        mGutsContainer.getLocationOnScreen(parentLoc);
-        v.getLocationOnScreen(targetLoc);
-        final int centerX = v.getWidth() / 2;
-        final int centerY = v.getHeight() / 2;
-        final int x = targetLoc[0] - parentLoc[0] + centerX;
-        final int y = targetLoc[1] - parentLoc[1] + centerY;
-        mGutsContainer.closeControls(x, y, save, false /* force */);
-    }
-
     @Override
     public void setGutsParent(NotificationGuts guts) {
         mGutsContainer = guts;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java
index dd5cb58..ec73a75 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/AppOpsInfoTest.java
@@ -144,7 +144,7 @@
         final View okButton = mAppOpsInfo.findViewById(R.id.ok);
         okButton.performClick();
         assertEquals(1, latch.getCount());
-        verify(mGutsParent, times(1)).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
+        verify(mGutsParent, times(1)).closeControls(eq(okButton), anyBoolean());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index b39de34..b1f67ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -173,7 +173,7 @@
         doAnswer((Answer<Object>) invocation -> {
             mNotificationInfo.handleCloseControls(true, false);
             return null;
-        }).when(mNotificationGuts).closeControls(anyInt(), anyInt(), eq(true), eq(false));
+        }).when(mNotificationGuts).closeControls(any(View.class), eq(true));
         // Our view is never attached to a window so the View#post methods in NotificationInfo never
         // get called. Setting this will skip the post and do the action immediately.
         mNotificationInfo.mSkipPost = true;
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index e066d99..a153d41 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -1894,6 +1894,8 @@
                 return runWaveform();
             } else if ("prebaked".equals(cmd)) {
                 return runPrebaked();
+            } else if ("capabilities".equals(cmd)) {
+                return runCapabilities();
             } else if ("cancel".equals(cmd)) {
                 cancelVibrate(mToken);
                 return 0;
@@ -2016,10 +2018,15 @@
             Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runPrebaked");
             try {
                 CommonOptions commonOptions = new CommonOptions();
+                boolean shouldFallback = false;
 
                 String opt;
                 while ((opt = getNextOption()) != null) {
-                    commonOptions.check(opt);
+                    if ("-b".equals(opt)) {
+                        shouldFallback = true;
+                    } else {
+                        commonOptions.check(opt);
+                    }
                 }
 
                 if (checkDoNotDisturb(commonOptions)) {
@@ -2033,8 +2040,7 @@
                     description = "Shell command";
                 }
 
-                VibrationEffect effect =
-                        VibrationEffect.get(id, false);
+                VibrationEffect effect = VibrationEffect.get(id, shouldFallback);
                 VibrationAttributes attrs = createVibrationAttributes(commonOptions);
                 vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command",
                         mToken);
@@ -2044,12 +2050,39 @@
             }
         }
 
+        private int runCapabilities() {
+            Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "runCapabilities");
+            try (PrintWriter pw = getOutPrintWriter();) {
+                pw.println("Vibrator capabilities:");
+                if (hasCapability(IVibrator.CAP_ALWAYS_ON_CONTROL)) {
+                    pw.println("  Always on effects");
+                }
+                if (hasCapability(IVibrator.CAP_COMPOSE_EFFECTS)) {
+                    pw.println("  Compose effects");
+                }
+                if (mSupportsAmplitudeControl || hasCapability(IVibrator.CAP_AMPLITUDE_CONTROL)) {
+                    pw.println("  Amplitude control");
+                }
+                if (mSupportsExternalControl || hasCapability(IVibrator.CAP_EXTERNAL_CONTROL)) {
+                    pw.println("  External control");
+                }
+                if (hasCapability(IVibrator.CAP_EXTERNAL_AMPLITUDE_CONTROL)) {
+                    pw.println("  External amplitude control");
+                }
+                pw.println("");
+                return 0;
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);
+            }
+        }
+
         private VibrationAttributes createVibrationAttributes(CommonOptions commonOptions) {
             final int flags = commonOptions.force
                     ? VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY
                     : 0;
             return new VibrationAttributes.Builder()
-                    .setUsage(VibrationAttributes.USAGE_UNKNOWN)
+                    // Used to apply Settings.System.HAPTIC_FEEDBACK_INTENSITY to scale effects.
+                    .setUsage(VibrationAttributes.USAGE_TOUCH)
                     .replaceFlags(flags)
                     .build();
         }
@@ -2062,19 +2095,26 @@
                 pw.println("    Prints this help text.");
                 pw.println("");
                 pw.println("  vibrate duration [description]");
-                pw.println("    Vibrates for duration milliseconds; ignored when device is on DND ");
-                pw.println("    (Do Not Disturb) mode.");
+                pw.println("    Vibrates for duration milliseconds; ignored when device is on ");
+                pw.println("    DND (Do Not Disturb) mode; touch feedback strength user setting ");
+                pw.println("    will be used to scale amplitude.");
                 pw.println("  waveform [-d description] [-r index] [-a] duration [amplitude] ...");
-                pw.println("    Vibrates for durations and amplitudes in list;");
-                pw.println("    ignored when device is on DND (Do Not Disturb) mode.");
+                pw.println("    Vibrates for durations and amplitudes in list; ignored when ");
+                pw.println("    device is on DND (Do Not Disturb) mode; touch feedback strength ");
+                pw.println("    user setting will be used to scale amplitude.");
                 pw.println("    If -r is provided, the waveform loops back to the specified");
                 pw.println("    index (e.g. 0 loops from the beginning)");
                 pw.println("    If -a is provided, the command accepts duration-amplitude pairs;");
                 pw.println("    otherwise, it accepts durations only and alternates off/on");
                 pw.println("    Duration is in milliseconds; amplitude is a scale of 1-255.");
-                pw.println("  prebaked effect-id [description]");
+                pw.println("  prebaked [-b] effect-id [description]");
                 pw.println("    Vibrates with prebaked effect; ignored when device is on DND ");
-                pw.println("    (Do Not Disturb) mode.");
+                pw.println("    (Do Not Disturb) mode; touch feedback strength user setting ");
+                pw.println("    will be used to scale amplitude.");
+                pw.println("    If -b is provided, the prebaked fallback effect will be played if");
+                pw.println("    the device doesn't support the given effect-id.");
+                pw.println("  capabilities");
+                pw.println("    Prints capabilities of this device.");
                 pw.println("  cancel");
                 pw.println("    Cancels any active vibration");
                 pw.println("Common Options:");
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 9476e92..5f63233 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -77,6 +77,7 @@
 import android.util.SparseArray;
 import android.util.Xml;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
@@ -114,7 +115,7 @@
     private static final String TAG = "UriGrantsManagerService";
     // Maximum number of persisted Uri grants a package is allowed
     private static final int MAX_PERSISTED_URI_GRANTS = 128;
-    private static final boolean ENABLE_DYNAMIC_PERMISSIONS = false;
+    private static final boolean ENABLE_DYNAMIC_PERMISSIONS = true;
 
     private final Object mLock = new Object();
     private final H mH;
@@ -122,6 +123,7 @@
     PackageManagerInternal mPmInternal;
 
     /** File storing persisted {@link #mGrantedUriPermissions}. */
+    @GuardedBy("mLock")
     private final AtomicFile mGrantFile;
 
     /** XML constants used in {@link #mGrantFile} */
@@ -142,6 +144,7 @@
      * This optimized lookup structure maps from {@link UriPermission#targetUid}
      * to {@link UriPermission#uri} to {@link UriPermission}.
      */
+    @GuardedBy("mLock")
     private final SparseArray<ArrayMap<GrantUri, UriPermission>>
             mGrantedUriPermissions = new SparseArray<>();
 
@@ -206,39 +209,44 @@
         }
     }
 
+    @Override
+    public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg,
+            Uri uri, final int modeFlags, int sourceUserId, int targetUserId) {
+        grantUriPermissionFromOwnerUnlocked(token, fromUid, targetPkg, uri, modeFlags, sourceUserId,
+                targetUserId);
+    }
+
     /**
      * @param uri This uri must NOT contain an embedded userId.
      * @param sourceUserId The userId in which the uri is to be resolved.
      * @param targetUserId The userId of the app that receives the grant.
      */
-    @Override
-    public void grantUriPermissionFromOwner(IBinder token, int fromUid, String targetPkg, Uri uri,
-            final int modeFlags, int sourceUserId, int targetUserId) {
+    private void grantUriPermissionFromOwnerUnlocked(IBinder token, int fromUid, String targetPkg,
+            Uri uri, final int modeFlags, int sourceUserId, int targetUserId) {
         targetUserId = mAmInternal.handleIncomingUser(Binder.getCallingPid(),
                 Binder.getCallingUid(), targetUserId, false, ALLOW_FULL_ONLY,
                 "grantUriPermissionFromOwner", null);
-        synchronized(mLock) {
-            UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
-            if (owner == null) {
-                throw new IllegalArgumentException("Unknown owner: " + token);
-            }
-            if (fromUid != Binder.getCallingUid()) {
-                if (Binder.getCallingUid() != myUid()) {
-                    // Only system code can grant URI permissions on behalf
-                    // of other users.
-                    throw new SecurityException("nice try");
-                }
-            }
-            if (targetPkg == null) {
-                throw new IllegalArgumentException("null target");
-            }
-            if (uri == null) {
-                throw new IllegalArgumentException("null uri");
-            }
 
-            grantUriPermission(fromUid, targetPkg, new GrantUri(sourceUserId, uri, modeFlags),
-                    modeFlags, owner, targetUserId);
+        UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
+        if (owner == null) {
+            throw new IllegalArgumentException("Unknown owner: " + token);
         }
+        if (fromUid != Binder.getCallingUid()) {
+            if (Binder.getCallingUid() != myUid()) {
+                // Only system code can grant URI permissions on behalf
+                // of other users.
+                throw new SecurityException("nice try");
+            }
+        }
+        if (targetPkg == null) {
+            throw new IllegalArgumentException("null target");
+        }
+        if (uri == null) {
+            throw new IllegalArgumentException("null uri");
+        }
+
+        grantUriPermissionUnlocked(fromUid, targetPkg, new GrantUri(sourceUserId, uri, modeFlags),
+                modeFlags, owner, targetUserId);
     }
 
     @Override
@@ -362,7 +370,7 @@
                 persistChanged |= prefixPerm.takePersistableModes(modeFlags);
             }
 
-            persistChanged |= maybePrunePersistedUriGrants(uid);
+            persistChanged |= maybePrunePersistedUriGrantsLocked(uid);
 
             if (persistChanged) {
                 schedulePersistUriGrants();
@@ -374,8 +382,8 @@
     public void clearGrantedUriPermissions(String packageName, int userId) {
         mAmInternal.enforceCallingPermission(
                 CLEAR_APP_GRANTED_URI_PERMISSIONS, "clearGrantedUriPermissions");
-        synchronized(mLock) {
-            removeUriPermissionsForPackage(packageName, userId, true, true);
+        synchronized (mLock) {
+            removeUriPermissionsForPackageLocked(packageName, userId, true, true);
         }
     }
 
@@ -416,11 +424,11 @@
 
             if (exactPerm != null) {
                 persistChanged |= exactPerm.releasePersistableModes(modeFlags);
-                removeUriPermissionIfNeeded(exactPerm);
+                removeUriPermissionIfNeededLocked(exactPerm);
             }
             if (prefixPerm != null) {
                 persistChanged |= prefixPerm.releasePersistableModes(modeFlags);
-                removeUriPermissionIfNeeded(prefixPerm);
+                removeUriPermissionIfNeededLocked(prefixPerm);
             }
 
             if (persistChanged) {
@@ -441,8 +449,9 @@
      * @param targetOnly When {@code true}, only remove permissions where the app is the target,
      * not source.
      */
-    void removeUriPermissionsForPackage(
-            String packageName, int userHandle, boolean persistable, boolean targetOnly) {
+    @GuardedBy("mLock")
+    private void removeUriPermissionsForPackageLocked(String packageName, int userHandle,
+            boolean persistable, boolean targetOnly) {
         if (userHandle == UserHandle.USER_ALL && packageName == null) {
             throw new IllegalArgumentException("Must narrow by either package or user");
         }
@@ -494,7 +503,9 @@
     }
 
     /** Returns if the ContentProvider has granted a uri to callingUid */
-    boolean checkAuthorityGrants(int callingUid, ProviderInfo cpi, int userId, boolean checkUser) {
+    @GuardedBy("mLock")
+    private boolean checkAuthorityGrantsLocked(int callingUid, ProviderInfo cpi, int userId,
+            boolean checkUser) {
         final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
         if (perms != null) {
             for (int i = perms.size() - 1; i >= 0; i--) {
@@ -530,7 +541,8 @@
      *
      * @return if any mutations occured that require persisting.
      */
-    private boolean maybePrunePersistedUriGrants(int uid) {
+    @GuardedBy("mLock")
+    private boolean maybePrunePersistedUriGrantsLocked(int uid) {
         final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(uid);
         if (perms == null) return false;
         if (perms.size() < MAX_PERSISTED_URI_GRANTS) return false;
@@ -552,14 +564,14 @@
             if (DEBUG) Slog.v(TAG, "Trimming grant created at " + perm.persistedCreateTime);
 
             perm.releasePersistableModes(~0);
-            removeUriPermissionIfNeeded(perm);
+            removeUriPermissionIfNeededLocked(perm);
         }
 
         return true;
     }
 
     /** Like checkGrantUriPermission, but takes an Intent. */
-    NeededUriGrants checkGrantUriPermissionFromIntent(int callingUid,
+    private NeededUriGrants checkGrantUriPermissionFromIntentUnlocked(int callingUid,
             String targetPkg, Intent intent, int mode, NeededUriGrants needed, int targetUserId) {
         if (DEBUG) Slog.v(TAG,
                 "Checking URI perm to data=" + (intent != null ? intent.getData() : null)
@@ -598,7 +610,8 @@
         }
         if (data != null) {
             GrantUri grantUri = GrantUri.resolve(contentUserHint, data, mode);
-            targetUid = checkGrantUriPermission(callingUid, targetPkg, grantUri, mode, targetUid);
+            targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg, grantUri, mode,
+                    targetUid);
             if (targetUid > 0) {
                 if (needed == null) {
                     needed = new NeededUriGrants(targetPkg, targetUid, mode);
@@ -611,7 +624,7 @@
                 Uri uri = clip.getItemAt(i).getUri();
                 if (uri != null) {
                     GrantUri grantUri = GrantUri.resolve(contentUserHint, uri, mode);
-                    targetUid = checkGrantUriPermission(callingUid, targetPkg,
+                    targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg,
                             grantUri, mode, targetUid);
                     if (targetUid > 0) {
                         if (needed == null) {
@@ -622,7 +635,7 @@
                 } else {
                     Intent clipIntent = clip.getItemAt(i).getIntent();
                     if (clipIntent != null) {
-                        NeededUriGrants newNeeded = checkGrantUriPermissionFromIntent(
+                        NeededUriGrants newNeeded = checkGrantUriPermissionFromIntentUnlocked(
                                 callingUid, targetPkg, clipIntent, mode, needed, targetUserId);
                         if (newNeeded != null) {
                             needed = newNeeded;
@@ -635,7 +648,8 @@
         return needed;
     }
 
-    void readGrantedUriPermissions() {
+    @GuardedBy("mLock")
+    private void readGrantedUriPermissionsLocked() {
         if (DEBUG) Slog.v(TAG, "readGrantedUriPermissions()");
 
         final long now = System.currentTimeMillis();
@@ -681,7 +695,7 @@
                             if (targetUid != -1) {
                                 final GrantUri grantUri = new GrantUri(sourceUserId, uri,
                                         prefix ? Intent.FLAG_GRANT_PREFIX_URI_PERMISSION : 0);
-                                final UriPermission perm = findOrCreateUriPermission(
+                                final UriPermission perm = findOrCreateUriPermissionLocked(
                                         sourcePkg, targetPkg, targetUid, grantUri);
                                 perm.initPersistedModes(modeFlags, createdTime);
                             }
@@ -703,7 +717,8 @@
         }
     }
 
-    private UriPermission findOrCreateUriPermission(String sourcePkg,
+    @GuardedBy("mLock")
+    private UriPermission findOrCreateUriPermissionLocked(String sourcePkg,
             String targetPkg, int targetUid, GrantUri grantUri) {
         ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
         if (targetUris == null) {
@@ -740,15 +755,18 @@
             return;
         }
 
-        final UriPermission perm = findOrCreateUriPermission(
-                pi.packageName, targetPkg, targetUid, grantUri);
+        final UriPermission perm;
+        synchronized (mLock) {
+            perm = findOrCreateUriPermissionLocked(pi.packageName, targetPkg, targetUid, grantUri);
+        }
         perm.grantModes(modeFlags, owner);
         mPmInternal.grantImplicitAccess(UserHandle.getUserId(targetUid), null,
                 UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false /*direct*/);
     }
 
     /** Like grantUriPermissionUnchecked, but takes an Intent. */
-    void grantUriPermissionUncheckedFromIntent(NeededUriGrants needed, UriPermissionOwner owner) {
+    private void grantUriPermissionUncheckedFromIntent(NeededUriGrants needed,
+            UriPermissionOwner owner) {
         if (needed == null) {
             return;
         }
@@ -759,7 +777,7 @@
         }
     }
 
-    void grantUriPermission(int callingUid, String targetPkg, GrantUri grantUri,
+    private void grantUriPermissionUnlocked(int callingUid, String targetPkg, GrantUri grantUri,
             final int modeFlags, UriPermissionOwner owner, int targetUserId) {
         if (targetPkg == null) {
             throw new NullPointerException("targetPkg");
@@ -767,7 +785,8 @@
         int targetUid = mPmInternal.getPackageUidInternal(targetPkg, MATCH_DEBUG_TRIAGED_MISSING,
                 targetUserId);
 
-        targetUid = checkGrantUriPermission(callingUid, targetPkg, grantUri, modeFlags, targetUid);
+        targetUid = checkGrantUriPermissionUnlocked(callingUid, targetPkg, grantUri, modeFlags,
+                targetUid);
         if (targetUid < 0) {
             return;
         }
@@ -775,7 +794,7 @@
         grantUriPermissionUnchecked(targetUid, targetPkg, grantUri, modeFlags, owner);
     }
 
-    void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri,
+    private void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri,
             final int modeFlags) {
         if (DEBUG) Slog.v(TAG, "Revoking all granted permissions to " + grantUri);
 
@@ -788,8 +807,19 @@
             return;
         }
 
+        final boolean callerHoldsPermissions = checkHoldingPermissionsUnlocked(pi, grantUri,
+                callingUid, modeFlags);
+        synchronized (mLock) {
+            revokeUriPermissionLocked(targetPackage, callingUid, grantUri, modeFlags,
+                    callerHoldsPermissions);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void revokeUriPermissionLocked(String targetPackage, int callingUid, GrantUri grantUri,
+            final int modeFlags, final boolean callerHoldsPermissions) {
         // Does the caller have this permission on the URI?
-        if (!checkHoldingPermissions(pi, grantUri, callingUid, modeFlags)) {
+        if (!callerHoldsPermissions) {
             // If they don't have direct access to the URI, then revoke any
             // ownerless URI permissions that have been granted to them.
             final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.get(callingUid);
@@ -861,7 +891,7 @@
      * the given {@link ProviderInfo}. Final permission checking is always done
      * in {@link ContentProvider}.
      */
-    private boolean checkHoldingPermissions(
+    private boolean checkHoldingPermissionsUnlocked(
             ProviderInfo pi, GrantUri grantUri, int uid, final int modeFlags) {
         if (DEBUG) Slog.v(TAG, "checkHoldingPermissions: uri=" + grantUri + " uid=" + uid);
         if (UserHandle.getUserId(uid) != grantUri.sourceUserId) {
@@ -870,11 +900,17 @@
                 return false;
             }
         }
-        return checkHoldingPermissionsInternal(pi, grantUri, uid, modeFlags, true);
+        return checkHoldingPermissionsInternalUnlocked(pi, grantUri, uid, modeFlags, true);
     }
 
-    private boolean checkHoldingPermissionsInternal(ProviderInfo pi,
+    private boolean checkHoldingPermissionsInternalUnlocked(ProviderInfo pi,
             GrantUri grantUri, int uid, final int modeFlags, boolean considerUidPermissions) {
+        // We must never hold our local mLock in this method, since we may need
+        // to call into ActivityManager for dynamic permission checks
+        if (Thread.holdsLock(mLock)) {
+            throw new IllegalStateException("Must never hold local mLock");
+        }
+
         if (pi.applicationInfo.uid == uid) {
             return true;
         } else if (!pi.exported) {
@@ -968,7 +1004,8 @@
         return readMet && writeMet && forceMet;
     }
 
-    private void removeUriPermissionIfNeeded(UriPermission perm) {
+    @GuardedBy("mLock")
+    private void removeUriPermissionIfNeededLocked(UriPermission perm) {
         if (perm.modeFlags != 0) {
             return;
         }
@@ -985,6 +1022,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) {
         final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid);
         if (targetUris != null) {
@@ -1020,7 +1058,7 @@
      * If you already know the uid of the target, you can supply it in
      * lastTargetUid else set that to -1.
      */
-    int checkGrantUriPermission(int callingUid, String targetPkg, GrantUri grantUri,
+    private int checkGrantUriPermissionUnlocked(int callingUid, String targetPkg, GrantUri grantUri,
             int modeFlags, int lastTargetUid) {
         if (!Intent.isAccessUriMode(modeFlags)) {
             return -1;
@@ -1076,7 +1114,7 @@
         boolean targetHoldsPermission = false;
         if (targetUid >= 0) {
             // First...  does the target actually need this permission?
-            if (checkHoldingPermissions(pi, grantUri, targetUid, modeFlags)) {
+            if (checkHoldingPermissionsUnlocked(pi, grantUri, targetUid, modeFlags)) {
                 // No need to grant the target this permission.
                 if (DEBUG) Slog.v(TAG,
                         "Target " + targetPkg + " already has full permission to " + grantUri);
@@ -1144,7 +1182,7 @@
          */
         boolean specialCrossUserGrant = targetUid >= 0
                 && UserHandle.getUserId(targetUid) != grantUri.sourceUserId
-                && checkHoldingPermissionsInternal(pi, grantUri, callingUid,
+                && checkHoldingPermissionsInternalUnlocked(pi, grantUri, callingUid,
                 modeFlags, false /*without considering the uid permissions*/);
 
         // Second...  is the provider allowing granting of URI permissions?
@@ -1179,9 +1217,13 @@
         }
 
         // Third...  does the caller itself have permission to access this uri?
-        if (!checkHoldingPermissions(pi, grantUri, callingUid, modeFlags)) {
+        if (!checkHoldingPermissionsUnlocked(pi, grantUri, callingUid, modeFlags)) {
             // Require they hold a strong enough Uri permission
-            if (!checkUriPermission(grantUri, callingUid, modeFlags)) {
+            final boolean res;
+            synchronized (mLock) {
+                res = checkUriPermissionLocked(grantUri, callingUid, modeFlags);
+            }
+            if (!res) {
                 if (android.Manifest.permission.MANAGE_DOCUMENTS.equals(pi.readPermission)) {
                     throw new SecurityException(
                             "UID " + callingUid + " does not have permission to " + grantUri
@@ -1200,13 +1242,14 @@
     /**
      * @param userId The userId in which the uri is to be resolved.
      */
-    int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, int modeFlags,
-            int userId) {
-        return checkGrantUriPermission(callingUid, targetPkg,
+    private int checkGrantUriPermissionUnlocked(int callingUid, String targetPkg, Uri uri,
+            int modeFlags, int userId) {
+        return checkGrantUriPermissionUnlocked(callingUid, targetPkg,
                 new GrantUri(userId, uri, modeFlags), modeFlags, -1);
     }
 
-    boolean checkUriPermission(GrantUri grantUri, int uid, final int modeFlags) {
+    @GuardedBy("mLock")
+    private boolean checkUriPermissionLocked(GrantUri grantUri, int uid, final int modeFlags) {
         final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
         final int minStrength = persistable ? UriPermission.STRENGTH_PERSISTABLE
                 : UriPermission.STRENGTH_OWNED;
@@ -1238,7 +1281,8 @@
         return false;
     }
 
-    private void writeGrantedUriPermissions() {
+    @GuardedBy("mLock")
+    private void writeGrantedUriPermissionsLocked() {
         if (DEBUG) Slog.v(TAG, "writeGrantedUriPermissions()");
 
         final long startTime = SystemClock.uptimeMillis();
@@ -1299,34 +1343,35 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case PERSIST_URI_GRANTS_MSG: {
-                    writeGrantedUriPermissions();
+                    synchronized (mLock) {
+                        writeGrantedUriPermissionsLocked();
+                    }
                     break;
                 }
             }
         }
     }
 
-    final class LocalService implements UriGrantsManagerInternal {
+    private final class LocalService implements UriGrantsManagerInternal {
         @Override
         public void removeUriPermissionIfNeeded(UriPermission perm) {
             synchronized (mLock) {
-                UriGrantsManagerService.this.removeUriPermissionIfNeeded(perm);
+                UriGrantsManagerService.this.removeUriPermissionIfNeededLocked(perm);
             }
         }
 
         @Override
         public void revokeUriPermission(String targetPackage, int callingUid, GrantUri grantUri,
                 int modeFlags) {
-            synchronized (mLock) {
-                UriGrantsManagerService.this.revokeUriPermission(
-                        targetPackage, callingUid, grantUri, modeFlags);
-            }
+            UriGrantsManagerService.this.revokeUriPermission(
+                    targetPackage, callingUid, grantUri, modeFlags);
         }
 
         @Override
         public boolean checkUriPermission(GrantUri grantUri, int uid, int modeFlags) {
             synchronized (mLock) {
-                return UriGrantsManagerService.this.checkUriPermission(grantUri, uid, modeFlags);
+                return UriGrantsManagerService.this.checkUriPermissionLocked(grantUri, uid,
+                        modeFlags);
             }
         }
 
@@ -1334,83 +1379,73 @@
         public int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, int modeFlags,
                 int userId) {
             enforceNotIsolatedCaller("checkGrantUriPermission");
-            synchronized (mLock) {
-                return UriGrantsManagerService.this.checkGrantUriPermission(
-                        callingUid, targetPkg, uri, modeFlags, userId);
-            }
+            return UriGrantsManagerService.this.checkGrantUriPermissionUnlocked(
+                    callingUid, targetPkg, uri, modeFlags, userId);
         }
 
         @Override
         public NeededUriGrants checkGrantUriPermissionFromIntent(Intent intent, int callingUid,
                 String targetPkg, int targetUserId) {
-            synchronized (mLock) {
-                final int mode = (intent != null) ? intent.getFlags() : 0;
-                return UriGrantsManagerService.this.checkGrantUriPermissionFromIntent(
-                        callingUid, targetPkg, intent, mode, null, targetUserId);
-            }
+            final int mode = (intent != null) ? intent.getFlags() : 0;
+            return UriGrantsManagerService.this.checkGrantUriPermissionFromIntentUnlocked(
+                    callingUid, targetPkg, intent, mode, null, targetUserId);
         }
 
         @Override
         public void grantUriPermissionUncheckedFromIntent(NeededUriGrants needed,
                 UriPermissionOwner owner) {
-            synchronized (mLock) {
-                UriGrantsManagerService.this.grantUriPermissionUncheckedFromIntent(needed, owner);
-            }
+            UriGrantsManagerService.this.grantUriPermissionUncheckedFromIntent(needed, owner);
         }
 
         @Override
         public void onSystemReady() {
             synchronized (mLock) {
-                UriGrantsManagerService.this.readGrantedUriPermissions();
+                UriGrantsManagerService.this.readGrantedUriPermissionsLocked();
             }
         }
 
         @Override
         public IBinder newUriPermissionOwner(String name) {
             enforceNotIsolatedCaller("newUriPermissionOwner");
-            synchronized(mLock) {
-                UriPermissionOwner owner = new UriPermissionOwner(this, name);
-                return owner.getExternalToken();
-            }
+            UriPermissionOwner owner = new UriPermissionOwner(this, name);
+            return owner.getExternalToken();
         }
 
         @Override
         public void removeUriPermissionsForPackage(String packageName, int userHandle,
                 boolean persistable, boolean targetOnly) {
-            synchronized(mLock) {
-                UriGrantsManagerService.this.removeUriPermissionsForPackage(
+            synchronized (mLock) {
+                UriGrantsManagerService.this.removeUriPermissionsForPackageLocked(
                         packageName, userHandle, persistable, targetOnly);
             }
         }
 
         @Override
         public void revokeUriPermissionFromOwner(IBinder token, Uri uri, int mode, int userId) {
-            synchronized(mLock) {
-                final UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
-                if (owner == null) {
-                    throw new IllegalArgumentException("Unknown owner: " + token);
-                }
+            final UriPermissionOwner owner = UriPermissionOwner.fromExternalToken(token);
+            if (owner == null) {
+                throw new IllegalArgumentException("Unknown owner: " + token);
+            }
 
-                if (uri == null) {
-                    owner.removeUriPermissions(mode);
-                } else {
-                    owner.removeUriPermission(new GrantUri(userId, uri, mode), mode);
-                }
+            if (uri == null) {
+                owner.removeUriPermissions(mode);
+            } else {
+                owner.removeUriPermission(new GrantUri(userId, uri, mode), mode);
             }
         }
 
         @Override
         public boolean checkAuthorityGrants(int callingUid, ProviderInfo cpi, int userId,
                 boolean checkUser) {
-            synchronized(mLock) {
-                return UriGrantsManagerService.this.checkAuthorityGrants(
+            synchronized (mLock) {
+                return UriGrantsManagerService.this.checkAuthorityGrantsLocked(
                         callingUid, cpi, userId, checkUser);
             }
         }
 
         @Override
         public void dump(PrintWriter pw, boolean dumpAll, String dumpPackage) {
-            synchronized(mLock) {
+            synchronized (mLock) {
                 boolean needSep = false;
                 boolean printedAnything = false;
                 if (mGrantedUriPermissions.size() > 0) {
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
index e86399e..62b6a65 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
@@ -60,14 +60,12 @@
 
 public class UriGrantsManagerServiceTest {
     private UriGrantsMockContext mContext;
-    private UriGrantsManagerService mService;
-    private UriGrantsManagerInternal mLocalService;
+    private UriGrantsManagerInternal mService;
 
     @Before
     public void setUp() throws Exception {
         mContext = new UriGrantsMockContext(InstrumentationRegistry.getContext());
-        mService = UriGrantsManagerService.createForTest(mContext.getFilesDir());
-        mLocalService = mService.getLocalService();
+        mService = UriGrantsManagerService.createForTest(mContext.getFilesDir()).getLocalService();
     }
 
     /**
@@ -80,8 +78,7 @@
         final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
 
         final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
-                UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null,
-                USER_PRIMARY);
+                intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY);
         assertEquals(PKG_SOCIAL, needed.targetPkg);
         assertEquals(UID_PRIMARY_SOCIAL, needed.targetUid);
         assertEquals(FLAG_READ, needed.flags);
@@ -98,8 +95,7 @@
         final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
 
         final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
-                UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null,
-                USER_SECONDARY);
+                intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_SECONDARY);
         assertEquals(PKG_SOCIAL, needed.targetPkg);
         assertEquals(UID_SECONDARY_SOCIAL, needed.targetUid);
         assertEquals(FLAG_READ, needed.flags);
@@ -113,8 +109,7 @@
     public void testNeeded_public() {
         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PUBLIC).addFlags(FLAG_READ);
         final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
-                UID_PRIMARY_PUBLIC, PKG_SOCIAL, intent, intent.getFlags(), null,
-                USER_PRIMARY);
+                intent, UID_PRIMARY_PUBLIC, PKG_SOCIAL, USER_PRIMARY);
         assertNull(needed);
     }
 
@@ -128,7 +123,7 @@
         final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PUBLIC, FLAG_READ);
 
         final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
-                UID_PRIMARY_PUBLIC, PKG_SOCIAL, intent, intent.getFlags(), null, USER_SECONDARY);
+                intent, UID_PRIMARY_PUBLIC, PKG_SOCIAL, USER_SECONDARY);
         assertEquals(PKG_SOCIAL, needed.targetPkg);
         assertEquals(UID_SECONDARY_SOCIAL, needed.targetUid);
         assertEquals(FLAG_READ, needed.flags);
@@ -143,7 +138,7 @@
         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PRIVATE).addFlags(FLAG_READ);
         try {
             mService.checkGrantUriPermissionFromIntent(
-                    UID_PRIMARY_PRIVATE, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY);
+                    intent, UID_PRIMARY_PRIVATE, PKG_SOCIAL, USER_PRIMARY);
             fail();
         } catch (SecurityException expected) {
         }
@@ -158,7 +153,7 @@
         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_FORCE)
                 .addFlags(FLAG_READ);
         final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
-                UID_PRIMARY_FORCE, PKG_FORCE, intent, intent.getFlags(), null, USER_PRIMARY);
+                intent, UID_PRIMARY_FORCE, PKG_FORCE, USER_PRIMARY);
         assertEquals(asSet(new GrantUri(USER_PRIMARY, URI_FORCE, 0)), needed.uris);
     }
 
@@ -172,15 +167,15 @@
         {
             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
                     .addFlags(FLAG_READ | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-            assertNull(mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_COMPLEX, PKG_SOCIAL,
-                    intent, intent.getFlags(), null, USER_PRIMARY));
+            assertNull(mService.checkGrantUriPermissionFromIntent(
+                    intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY));
         }
         {
             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
                     .addFlags(FLAG_READ | FLAG_PREFIX);
             try {
-                mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_COMPLEX, PKG_SOCIAL,
-                        intent, intent.getFlags(), null, USER_PRIMARY);
+                mService.checkGrantUriPermissionFromIntent(
+                        intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
                 fail();
             } catch (SecurityException expected) {
             }
@@ -189,8 +184,8 @@
             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
                     .addFlags(FLAG_READ | FLAG_PERSISTABLE);
             try {
-                mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_COMPLEX, PKG_SOCIAL,
-                        intent, intent.getFlags(), null, USER_PRIMARY);
+                mService.checkGrantUriPermissionFromIntent(
+                        intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
                 fail();
             } catch (SecurityException expected) {
             }
@@ -209,8 +204,7 @@
             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
                     .addFlags(FLAG_READ);
             final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
-                    UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null,
-                    USER_SECONDARY);
+                    intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_SECONDARY);
             assertEquals(FLAG_READ, needed.flags);
         }
         {
@@ -218,8 +212,7 @@
                     .addFlags(FLAG_READ | FLAG_PREFIX);
             try {
                 mService.checkGrantUriPermissionFromIntent(
-                        UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null,
-                        USER_SECONDARY);
+                        intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_SECONDARY);
                 fail();
             } catch (SecurityException expected) {
             }
@@ -229,8 +222,7 @@
                     .addFlags(FLAG_READ | FLAG_PERSISTABLE);
             try {
                 mService.checkGrantUriPermissionFromIntent(
-                        UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null,
-                        USER_SECONDARY);
+                        intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_SECONDARY);
                 fail();
             } catch (SecurityException expected) {
             }
@@ -248,21 +240,21 @@
             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
                     .addFlags(FLAG_READ);
             final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
-                    UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY);
+                    intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
             assertEquals(asSet(new GrantUri(USER_PRIMARY, uri, 0)), needed.uris);
         }
         {
             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
                     .addFlags(FLAG_READ | FLAG_PREFIX);
             final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
-                    UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY);
+                    intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
             assertEquals(asSet(new GrantUri(USER_PRIMARY, uri, FLAG_PREFIX)), needed.uris);
         }
         {
             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
                     .addFlags(FLAG_READ | FLAG_PERSISTABLE);
             final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
-                    UID_PRIMARY_COMPLEX, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY);
+                    intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
             assertEquals(asSet(new GrantUri(USER_PRIMARY, uri, 0)), needed.uris);
         }
     }
@@ -284,8 +276,8 @@
             // When granting towards primary, persistable can't be honored so
             // the entire grant fails
             try {
-                mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_CAMERA, PKG_SOCIAL, intent,
-                        intent.getFlags(), null, USER_PRIMARY);
+                mService.checkGrantUriPermissionFromIntent(
+                        intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY);
                 fail();
             } catch (SecurityException expected) {
             }
@@ -294,8 +286,8 @@
             // When granting towards secondary, persistable can't be honored so
             // the entire grant fails
             try {
-                mService.checkGrantUriPermissionFromIntent(UID_PRIMARY_CAMERA, PKG_SOCIAL, intent,
-                        intent.getFlags(), null, USER_SECONDARY);
+                mService.checkGrantUriPermissionFromIntent(
+                        intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_SECONDARY);
                 fail();
             } catch (SecurityException expected) {
             }
@@ -310,18 +302,16 @@
     public void testGrant_overlap() {
         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PHOTO_1).addFlags(FLAG_READ);
 
-        final UriPermissionOwner activity = new UriPermissionOwner(mLocalService, "activity");
-        final UriPermissionOwner service = new UriPermissionOwner(mLocalService, "service");
+        final UriPermissionOwner activity = new UriPermissionOwner(mService, "activity");
+        final UriPermissionOwner service = new UriPermissionOwner(mService, "service");
 
         final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
 
         // Grant read via activity and write via service
         mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
-                UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY),
-                activity);
+                intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), activity);
         mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
-                UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY),
-                service);
+                intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), service);
 
         // Verify that everything is good with the world
         assertTrue(mService.checkUriPermission(expectedGrant, UID_PRIMARY_SOCIAL, FLAG_READ));
@@ -338,7 +328,7 @@
     @Test
     public void testCheckAuthorityGrants() {
         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PHOTO_1).addFlags(FLAG_READ);
-        final UriPermissionOwner owner = new UriPermissionOwner(mLocalService, "primary");
+        final UriPermissionOwner owner = new UriPermissionOwner(mService, "primary");
 
         final ProviderInfo cameraInfo = mContext.mPmInternal.resolveContentProvider(
                 PKG_CAMERA, 0, USER_PRIMARY);
@@ -355,8 +345,7 @@
 
         // Granting primary camera to primary social
         mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
-                UID_PRIMARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY),
-                owner);
+                intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), owner);
         assertTrue(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
                 cameraInfo, USER_PRIMARY, true));
         assertFalse(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
@@ -368,8 +357,7 @@
 
         // Granting secondary camera to primary social
         mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
-                UID_SECONDARY_CAMERA, PKG_SOCIAL, intent, intent.getFlags(), null, USER_PRIMARY),
-                owner);
+                intent, UID_SECONDARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), owner);
         assertTrue(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
                 cameraInfo, USER_PRIMARY, true));
         assertTrue(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,