Merge "Resolve message/conversation image Uris with the correct user id" into tm-qpr-dev
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index 3f2fa21..16b18c85 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -31,6 +31,7 @@
 import android.os.Process;
 import android.permission.PermissionManager;
 import android.util.ArraySet;
+import android.util.Log;
 
 import com.android.internal.annotations.Immutable;
 
@@ -87,6 +88,8 @@
  */
 @Immutable
 public final class AttributionSource implements Parcelable {
+    private static final String TAG = "AttributionSource";
+
     private static final String DESCRIPTOR = "android.content.AttributionSource";
 
     private static final Binder sDefaultToken = new Binder(DESCRIPTOR);
@@ -154,9 +157,20 @@
     AttributionSource(@NonNull Parcel in) {
         this(AttributionSourceState.CREATOR.createFromParcel(in));
 
-        // Since we just unpacked this object as part of it transiting a Binder
-        // call, this is the perfect time to enforce that its UID and PID can be trusted
-        enforceCallingUidAndPid();
+        if (!Binder.isDirectlyHandlingTransaction()) {
+            Log.e(TAG, "Unable to verify calling UID #" + mAttributionSourceState.uid + " PID #"
+                    + mAttributionSourceState.pid + " when not handling Binder transaction; "
+                    + "clearing.");
+            mAttributionSourceState.pid = -1;
+            mAttributionSourceState.uid = -1;
+            mAttributionSourceState.packageName = null;
+            mAttributionSourceState.attributionTag = null;
+            mAttributionSourceState.next = null;
+        } else {
+            // Since we just unpacked this object as part of it transiting a Binder
+            // call, this is the perfect time to enforce that its UID and PID can be trusted
+            enforceCallingUidAndPid();
+        }
     }
 
     /** @hide */
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f224f8a1..2ec2b3b 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2740,6 +2740,16 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: This device is capable of launching apps in automotive display
+     * compatibility mode.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_CAR_DISPLAY_COMPATIBILITY =
+            "android.software.car.display_compatibility";
+
+    /**
+     * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device supports
      * {@link android.security.identity.IdentityCredentialStore} implemented in secure hardware
      * at the given feature version.
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
index 30ee147..2a2882c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
@@ -18,16 +18,10 @@
 
 import android.content.Context
 import android.content.res.Configuration
-import android.database.ContentObserver
-import android.net.Uri
-import android.os.Handler
-import android.os.UserHandle
-import android.provider.Settings
 import android.view.View
 import android.view.ViewGroup
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.media.dagger.MediaModule.KEYGUARD
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.StatusBarState
@@ -36,7 +30,6 @@
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.LargeScreenUtils
-import com.android.systemui.util.settings.SecureSettings
 import javax.inject.Inject
 import javax.inject.Named
 
@@ -52,8 +45,6 @@
     private val bypassController: KeyguardBypassController,
     private val statusBarStateController: SysuiStatusBarStateController,
     private val context: Context,
-    private val secureSettings: SecureSettings,
-    @Main private val handler: Handler,
     configurationController: ConfigurationController,
 ) {
 
@@ -77,26 +68,6 @@
             }
         )
 
-        val settingsObserver: ContentObserver =
-            object : ContentObserver(handler) {
-                override fun onChange(selfChange: Boolean, uri: Uri?) {
-                    if (uri == lockScreenMediaPlayerUri) {
-                        allowMediaPlayerOnLockScreen =
-                            secureSettings.getBoolForUser(
-                                Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
-                                true,
-                                UserHandle.USER_CURRENT
-                            )
-                        refreshMediaPosition()
-                    }
-                }
-            }
-        secureSettings.registerContentObserverForUser(
-            Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
-            settingsObserver,
-            UserHandle.USER_ALL
-        )
-
         // First let's set the desired state that we want for this host
         mediaHost.expansion = MediaHostState.EXPANDED
         mediaHost.showsOnlyActiveMedia = true
@@ -133,16 +104,6 @@
         private set
     private var splitShadeContainer: ViewGroup? = null
 
-    /** Track the media player setting status on lock screen. */
-    private var allowMediaPlayerOnLockScreen: Boolean =
-        secureSettings.getBoolForUser(
-            Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
-            true,
-            UserHandle.USER_CURRENT
-        )
-    private val lockScreenMediaPlayerUri =
-        secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
-
     /**
      * Attaches media container in single pane mode, situated at the top of the notifications list
      */
@@ -202,7 +163,6 @@
             mediaHost.visible &&
                 !bypassController.bypassEnabled &&
                 keyguardOrUserSwitcher &&
-                allowMediaPlayerOnLockScreen &&
                 shouldBeVisibleForSplitShade()
         if (visible) {
             showMediaPlayer()
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index 54237ce..f0ff129 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -104,7 +104,7 @@
 ) {
 
     /** Track the media player setting status on lock screen. */
-    private var allowMediaPlayerOnLockScreen: Boolean = true
+    private var allowMediaPlayerOnLockScreen: Boolean = getMediaLockScreenSetting()
     private val lockScreenMediaPlayerUri =
         secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
 
@@ -462,6 +462,7 @@
                     }
                     mediaCarouselController.mediaCarouselScrollHandler.visibleToUser =
                         isVisibleToUser()
+                    mediaCarouselController.updateHostVisibility()
                 }
 
                 override fun onDozeAmountChanged(linear: Float, eased: Float) {
@@ -538,7 +539,6 @@
         mediaCarouselController.updateHostVisibility = {
             mediaHosts.forEach { it?.updateViewVisibility() }
         }
-
         panelEventsEvents.addShadeStateEventsListener(
             object : ShadeStateEventsListener {
                 override fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {
@@ -552,12 +552,8 @@
             object : ContentObserver(handler) {
                 override fun onChange(selfChange: Boolean, uri: Uri?) {
                     if (uri == lockScreenMediaPlayerUri) {
-                        allowMediaPlayerOnLockScreen =
-                            secureSettings.getBoolForUser(
-                                Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
-                                true,
-                                UserHandle.USER_CURRENT
-                            )
+                        allowMediaPlayerOnLockScreen = getMediaLockScreenSetting()
+                        mediaCarouselController.updateHostVisibility()
                     }
                 }
             }
@@ -568,6 +564,14 @@
         )
     }
 
+    private fun getMediaLockScreenSetting(): Boolean {
+        return secureSettings.getBoolForUser(
+            Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+            true,
+            UserHandle.USER_CURRENT
+        )
+    }
+
     private fun updateConfiguration() {
         distanceForFullShadeTransition =
             context.resources.getDimensionPixelSize(
@@ -607,6 +611,13 @@
         mediaCarouselController.closeGuts()
     }
 
+    /** Return true if the carousel should be hidden because lockscreen is currently visible */
+    fun isLockedAndHidden(): Boolean {
+        return !allowMediaPlayerOnLockScreen &&
+            (statusbarState == StatusBarState.SHADE_LOCKED ||
+                statusbarState == StatusBarState.KEYGUARD)
+    }
+
     private fun createUniqueObjectHost(): UniqueObjectHostView {
         val viewHost = UniqueObjectHostView(context)
         viewHost.addOnAttachStateChangeListener(
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
index be570b4..26580e5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
@@ -199,7 +199,9 @@
      */
     fun updateViewVisibility() {
         state.visible =
-            if (showsOnlyActiveMedia) {
+            if (mediaHierarchyManager.isLockedAndHidden()) {
+                false
+            } else if (showsOnlyActiveMedia) {
                 mediaDataManager.hasActiveMediaOrRecommendation()
             } else {
                 mediaDataManager.hasAnyMediaOrRecommendation()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
index b40ebc9..41b3fe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
@@ -16,7 +16,6 @@
 
 package com.android.systemui.media.controls.ui
 
-import android.provider.Settings
 import android.test.suitebuilder.annotation.SmallTest
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
@@ -32,8 +31,6 @@
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.animation.UniqueObjectHostView
 import com.android.systemui.util.mockito.whenever
-import com.android.systemui.util.settings.FakeSettings
-import com.android.systemui.utils.os.FakeHandler
 import com.google.common.truth.Truth.assertThat
 import junit.framework.Assert.assertTrue
 import org.junit.Before
@@ -60,10 +57,7 @@
 
     private val mediaContainerView: MediaContainerView = MediaContainerView(context, null)
     private val hostView = UniqueObjectHostView(context)
-    private val settings = FakeSettings()
     private lateinit var keyguardMediaController: KeyguardMediaController
-    private lateinit var testableLooper: TestableLooper
-    private lateinit var fakeHandler: FakeHandler
     private lateinit var statusBarStateListener: StatusBarStateController.StateListener
 
     @Before
@@ -79,16 +73,12 @@
         whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
         whenever(mediaHost.hostView).thenReturn(hostView)
         hostView.layoutParams = FrameLayout.LayoutParams(100, 100)
-        testableLooper = TestableLooper.get(this)
-        fakeHandler = FakeHandler(testableLooper.looper)
         keyguardMediaController =
             KeyguardMediaController(
                 mediaHost,
                 bypassController,
                 statusBarStateController,
                 context,
-                settings,
-                fakeHandler,
                 configurationController,
             )
         keyguardMediaController.attachSinglePaneContainer(mediaContainerView)
@@ -118,24 +108,6 @@
     }
 
     @Test
-    fun testHiddenOnKeyguard_whenMediaOnLockScreenDisabled() {
-        settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 0)
-
-        keyguardMediaController.refreshMediaPosition()
-
-        assertThat(mediaContainerView.visibility).isEqualTo(GONE)
-    }
-
-    @Test
-    fun testAvailableOnKeyguard_whenMediaOnLockScreenEnabled() {
-        settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1)
-
-        keyguardMediaController.refreshMediaPosition()
-
-        assertThat(mediaContainerView.visibility).isEqualTo(VISIBLE)
-    }
-
-    @Test
     fun testActivatesSplitShadeContainerInSplitShadeMode() {
         val splitShadeContainer = FrameLayout(context)
         keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
index eb78ded..c2a7210 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
@@ -124,6 +124,7 @@
         verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
         verify(statusBarStateController).addCallback(statusBarCallback.capture())
         verify(dreamOverlayStateController).addCallback(dreamOverlayCallback.capture())
+        whenever(mediaCarouselController.updateHostVisibility).thenReturn({})
         setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN, LOCKSCREEN_TOP)
         setupHost(qsHost, MediaHierarchyManager.LOCATION_QS, QS_TOP)
         setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS, QQS_TOP)
@@ -470,6 +471,55 @@
             )
     }
 
+    @Test
+    fun keyguardState_allowedOnLockscreen_updateVisibility() {
+        settings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, true)
+        clearInvocations(mediaCarouselController)
+
+        statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+        statusBarCallback.value.onStateChanged(StatusBarState.KEYGUARD)
+
+        verify(mediaCarouselController).updateHostVisibility
+        assertThat(mediaHierarchyManager.isLockedAndHidden()).isFalse()
+    }
+
+    @Test
+    fun keyguardState_notAllowedOnLockscreen_updateVisibility() {
+        settings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false)
+        clearInvocations(mediaCarouselController)
+
+        statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+        statusBarCallback.value.onStateChanged(StatusBarState.KEYGUARD)
+
+        verify(mediaCarouselController).updateHostVisibility
+        assertThat(mediaHierarchyManager.isLockedAndHidden()).isTrue()
+    }
+
+    @Test
+    fun keyguardGone_updateVisibility() {
+        settings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false)
+        clearInvocations(mediaCarouselController)
+
+        statusBarCallback.value.onStatePreChange(StatusBarState.KEYGUARD, StatusBarState.SHADE)
+        statusBarCallback.value.onStateChanged(StatusBarState.SHADE)
+
+        verify(mediaCarouselController).updateHostVisibility
+        assertThat(mediaHierarchyManager.isLockedAndHidden()).isFalse()
+    }
+
+    @Test
+    fun lockscreenSettingChanged_updateVisibility() {
+        settings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, true)
+        statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+        statusBarCallback.value.onStateChanged(StatusBarState.KEYGUARD)
+        clearInvocations(mediaCarouselController)
+
+        settings.putBool(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, false)
+
+        verify(mediaCarouselController).updateHostVisibility
+        assertThat(mediaHierarchyManager.isLockedAndHidden()).isTrue()
+    }
+
     private fun enableSplitShade() {
         context
             .getOrCreateTestableResources()
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 1c3564b..bc13f10 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3561,6 +3561,11 @@
 
             // Strip auth token from result.
             result.remove(AccountManager.KEY_AUTHTOKEN);
+            if (!checkKeyIntent(Binder.getCallingUid(), result)) {
+                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                        "invalid intent in bundle returned");
+                return;
+            }
 
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Log.v(TAG,
@@ -5146,6 +5151,11 @@
                     } else {
                         if (mStripAuthTokenFromResult) {
                             result.remove(AccountManager.KEY_AUTHTOKEN);
+                            if (!checkKeyIntent(Binder.getCallingUid(), result)) {
+                                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                                        "invalid intent in bundle returned");
+                                return;
+                            }
                         }
                         if (Log.isLoggable(TAG, Log.VERBOSE)) {
                             Log.v(TAG, getClass().getSimpleName()
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 8dadd31..96c34db 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -678,6 +678,7 @@
                 // TODO: switch this back to SecurityException
                 Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
                         + permName);
+                return;
             }
             mRegistry.removePermission(permName);
         }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b9d43d9..bc8e235 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -3296,8 +3296,10 @@
             return false;
         }
         if (doAnimation) {
-            mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
-            if (!isAnimating(TRANSITION | PARENTS)) {
+            // If a hide animation is applied, then let onAnimationFinished
+            // -> checkPolicyVisibilityChange hide the window. Otherwise make doAnimation false
+            // to commit invisible immediately.
+            if (!mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false /* isEntrance */)) {
                 doAnimation = false;
             }
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 219f441..44ae8dd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -227,6 +227,26 @@
         assertTrue(window.isOnScreen());
         window.hide(false /* doAnimation */, false /* requestAnim */);
         assertFalse(window.isOnScreen());
+
+        // Verifies that a window without animation can be hidden even if its parent is animating.
+        window.show(false /* doAnimation */, false /* requestAnim */);
+        assertTrue(window.isVisibleByPolicy());
+        window.getParent().startAnimation(mTransaction, mock(AnimationAdapter.class),
+                false /* hidden */, SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION);
+        window.mAttrs.windowAnimations = 0;
+        window.hide(true /* doAnimation */, true /* requestAnim */);
+        assertFalse(window.isSelfAnimating(0, SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION));
+        assertFalse(window.isVisibleByPolicy());
+        assertFalse(window.isOnScreen());
+
+        // Verifies that a window with animation can be hidden after the hide animation is finished.
+        window.show(false /* doAnimation */, false /* requestAnim */);
+        window.mAttrs.windowAnimations = android.R.style.Animation_Dialog;
+        window.hide(true /* doAnimation */, true /* requestAnim */);
+        assertTrue(window.isSelfAnimating(0, SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION));
+        assertTrue(window.isVisibleByPolicy());
+        window.cancelAnimation();
+        assertFalse(window.isVisibleByPolicy());
     }
 
     @Test
diff --git a/tests/BootImageProfileTest/AndroidTest.xml b/tests/BootImageProfileTest/AndroidTest.xml
index 7e97fa3..50f323c 100644
--- a/tests/BootImageProfileTest/AndroidTest.xml
+++ b/tests/BootImageProfileTest/AndroidTest.xml
@@ -14,6 +14,7 @@
      limitations under the License.
 -->
 <configuration description="Config for BootImageProfileTest">
+     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
      <!-- do not use DeviceSetup#set-property because it reboots the device b/136200738.
          furthermore the changes in /data/local.prop don't actually seem to get picked up.
     -->