Merge "Tapping dream media chip opens media instead of UMO if flag is set." into tm-qpr-dev
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamMediaEntryComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamMediaEntryComplication.java
index 21a51d1..c07d402 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamMediaEntryComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamMediaEntryComplication.java
@@ -18,13 +18,21 @@
 
 import static com.android.systemui.dreams.complication.dagger.DreamMediaEntryComplicationComponent.DreamMediaEntryModule.DREAM_MEDIA_ENTRY_VIEW;
 import static com.android.systemui.dreams.complication.dagger.RegisteredComplicationsModule.DREAM_MEDIA_ENTRY_LAYOUT_PARAMS;
+import static com.android.systemui.flags.Flags.DREAM_MEDIA_TAP_TO_OPEN;
 
+import android.app.PendingIntent;
 import android.util.Log;
 import android.view.View;
 
+import com.android.systemui.ActivityIntentHelper;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.dreams.complication.dagger.DreamMediaEntryComplicationComponent;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.media.MediaCarouselController;
 import com.android.systemui.media.dream.MediaDreamComplication;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.ViewController;
 
 import javax.inject.Inject;
@@ -87,6 +95,15 @@
 
         private final DreamOverlayStateController mDreamOverlayStateController;
         private final MediaDreamComplication mMediaComplication;
+        private final MediaCarouselController mMediaCarouselController;
+
+        private final ActivityStarter mActivityStarter;
+        private final ActivityIntentHelper mActivityIntentHelper;
+        private final KeyguardStateController mKeyguardStateController;
+        private final NotificationLockscreenUserManager mLockscreenUserManager;
+
+        private final FeatureFlags mFeatureFlags;
+        private boolean mIsTapToOpenEnabled;
 
         private boolean mMediaComplicationAdded;
 
@@ -94,15 +111,28 @@
         DreamMediaEntryViewController(
                 @Named(DREAM_MEDIA_ENTRY_VIEW) View view,
                 DreamOverlayStateController dreamOverlayStateController,
-                MediaDreamComplication mediaComplication) {
+                MediaDreamComplication mediaComplication,
+                MediaCarouselController mediaCarouselController,
+                ActivityStarter activityStarter,
+                ActivityIntentHelper activityIntentHelper,
+                KeyguardStateController keyguardStateController,
+                NotificationLockscreenUserManager lockscreenUserManager,
+                FeatureFlags featureFlags) {
             super(view);
             mDreamOverlayStateController = dreamOverlayStateController;
             mMediaComplication = mediaComplication;
+            mMediaCarouselController = mediaCarouselController;
+            mActivityStarter = activityStarter;
+            mActivityIntentHelper = activityIntentHelper;
+            mKeyguardStateController = keyguardStateController;
+            mLockscreenUserManager = lockscreenUserManager;
+            mFeatureFlags = featureFlags;
             mView.setOnClickListener(this::onClickMediaEntry);
         }
 
         @Override
         protected void onViewAttached() {
+            mIsTapToOpenEnabled = mFeatureFlags.isEnabled(DREAM_MEDIA_TAP_TO_OPEN);
         }
 
         @Override
@@ -113,6 +143,31 @@
         private void onClickMediaEntry(View v) {
             if (DEBUG) Log.d(TAG, "media entry complication tapped");
 
+            if (mIsTapToOpenEnabled) {
+                final PendingIntent clickIntent =
+                        mMediaCarouselController.getCurrentVisibleMediaContentIntent();
+
+                if (clickIntent == null) {
+                    return;
+                }
+
+                // See StatusBarNotificationActivityStarter#onNotificationClicked
+                final boolean showOverLockscreen = mKeyguardStateController.isShowing()
+                        && mActivityIntentHelper.wouldShowOverLockscreen(clickIntent.getIntent(),
+                        mLockscreenUserManager.getCurrentUserId());
+
+                if (showOverLockscreen) {
+                    mActivityStarter.startActivity(clickIntent.getIntent(),
+                            /* dismissShade */ true,
+                            /* animationController */ null,
+                            /* showOverLockscreenWhenLocked */ true);
+                } else {
+                    mActivityStarter.postStartActivityDismissingKeyguard(clickIntent, null);
+                }
+
+                return;
+            }
+
             if (!mMediaComplicationAdded) {
                 addMediaComplication();
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 938332d..48f5f9e 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -200,7 +200,8 @@
     public static final UnreleasedFlag MEDIA_SESSION_ACTIONS = new UnreleasedFlag(901);
     public static final ReleasedFlag MEDIA_NEARBY_DEVICES = new ReleasedFlag(903);
     public static final ReleasedFlag MEDIA_MUTE_AWAIT = new ReleasedFlag(904);
-    public static final UnreleasedFlag MEDIA_DREAM_COMPLICATION = new UnreleasedFlag(905);
+    public static final UnreleasedFlag DREAM_MEDIA_COMPLICATION = new UnreleasedFlag(905);
+    public static final UnreleasedFlag DREAM_MEDIA_TAP_TO_OPEN = new UnreleasedFlag(906);
 
     // 1000 - dock
     public static final ReleasedFlag SIMULATE_DOCK_THROUGH_CHARGING =
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index e25f5da..f8c6a57 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -1,5 +1,6 @@
 package com.android.systemui.media
 
+import android.app.PendingIntent
 import android.content.Context
 import android.content.Intent
 import android.content.res.ColorStateList
@@ -945,6 +946,11 @@
         mediaManager.onSwipeToDismiss()
     }
 
+    fun getCurrentVisibleMediaContentIntent(): PendingIntent? {
+        return MediaPlayerData.playerKeys()
+                .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)?.data?.clickIntent
+    }
+
     override fun dump(pw: PrintWriter, args: Array<out String>) {
         pw.apply {
             println("keysNeedRemoval: $keysNeedRemoval")
diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
index dc1488e..53b4d43 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.media.dream;
 
-import static com.android.systemui.flags.Flags.MEDIA_DREAM_COMPLICATION;
+import static com.android.systemui.flags.Flags.DREAM_MEDIA_COMPLICATION;
 
 import android.content.Context;
 import android.util.Log;
@@ -77,7 +77,7 @@
         public void onMediaDataLoaded(@NonNull String key, @Nullable String oldKey,
                 @NonNull MediaData data, boolean immediately, int receivedSmartspaceCardLatency,
                 boolean isSsReactivated) {
-            if (!mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)) {
+            if (!mFeatureFlags.isEnabled(DREAM_MEDIA_COMPLICATION)) {
                 return;
             }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamMediaEntryComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamMediaEntryComplicationTest.java
index bc94440..522b5b5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamMediaEntryComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamMediaEntryComplicationTest.java
@@ -16,17 +16,28 @@
 
 package com.android.systemui.dreams.complication;
 
-import static org.mockito.Mockito.verify;
+import static com.android.systemui.flags.Flags.DREAM_MEDIA_TAP_TO_OPEN;
 
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.PendingIntent;
+import android.content.Intent;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.view.View;
 
 import androidx.test.filters.SmallTest;
 
+import com.android.systemui.ActivityIntentHelper;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dreams.DreamOverlayStateController;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.media.MediaCarouselController;
 import com.android.systemui.media.dream.MediaDreamComplication;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.NotificationLockscreenUserManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -48,21 +59,52 @@
     @Mock
     private MediaDreamComplication mMediaComplication;
 
+    @Mock
+    private MediaCarouselController mMediaCarouselController;
+
+    @Mock
+    private ActivityStarter mActivityStarter;
+
+    @Mock
+    private ActivityIntentHelper mActivityIntentHelper;
+
+    @Mock
+    private KeyguardStateController mKeyguardStateController;
+
+    @Mock
+    private NotificationLockscreenUserManager mLockscreenUserManager;
+
+    @Mock
+    private FeatureFlags mFeatureFlags;
+
+    @Mock
+    private PendingIntent mPendingIntent;
+
+    private final Intent mIntent = new Intent("android.test.TEST_ACTION");
+    private final Integer mCurrentUserId = 99;
+
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
+        when(mFeatureFlags.isEnabled(DREAM_MEDIA_TAP_TO_OPEN)).thenReturn(false);
     }
 
     /**
      * Ensures clicking media entry chip adds/removes media complication.
      */
     @Test
-    public void testClick() {
+    public void testClickToOpenUMO() {
         final DreamMediaEntryComplication.DreamMediaEntryViewController viewController =
                 new DreamMediaEntryComplication.DreamMediaEntryViewController(
                         mView,
                         mDreamOverlayStateController,
-                        mMediaComplication);
+                        mMediaComplication,
+                        mMediaCarouselController,
+                        mActivityStarter,
+                        mActivityIntentHelper,
+                        mKeyguardStateController,
+                        mLockscreenUserManager,
+                        mFeatureFlags);
 
         final ArgumentCaptor<View.OnClickListener> clickListenerCaptor =
                 ArgumentCaptor.forClass(View.OnClickListener.class);
@@ -85,10 +127,90 @@
                 new DreamMediaEntryComplication.DreamMediaEntryViewController(
                         mView,
                         mDreamOverlayStateController,
-                        mMediaComplication);
+                        mMediaComplication,
+                        mMediaCarouselController,
+                        mActivityStarter,
+                        mActivityIntentHelper,
+                        mKeyguardStateController,
+                        mLockscreenUserManager,
+                        mFeatureFlags);
 
         viewController.onViewDetached();
         verify(mView).setSelected(false);
         verify(mDreamOverlayStateController).removeComplication(mMediaComplication);
     }
+
+    /**
+     * Ensures clicking media entry chip opens media when flag is set.
+     */
+    @Test
+    public void testClickToOpenMediaOverLockscreen() {
+        when(mFeatureFlags.isEnabled(DREAM_MEDIA_TAP_TO_OPEN)).thenReturn(true);
+
+        when(mMediaCarouselController.getCurrentVisibleMediaContentIntent()).thenReturn(
+                mPendingIntent);
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        when(mPendingIntent.getIntent()).thenReturn(mIntent);
+        when(mLockscreenUserManager.getCurrentUserId()).thenReturn(mCurrentUserId);
+
+        final DreamMediaEntryComplication.DreamMediaEntryViewController viewController =
+                new DreamMediaEntryComplication.DreamMediaEntryViewController(
+                        mView,
+                        mDreamOverlayStateController,
+                        mMediaComplication,
+                        mMediaCarouselController,
+                        mActivityStarter,
+                        mActivityIntentHelper,
+                        mKeyguardStateController,
+                        mLockscreenUserManager,
+                        mFeatureFlags);
+        viewController.onViewAttached();
+
+        final ArgumentCaptor<View.OnClickListener> clickListenerCaptor =
+                ArgumentCaptor.forClass(View.OnClickListener.class);
+        verify(mView).setOnClickListener(clickListenerCaptor.capture());
+
+        when(mActivityIntentHelper.wouldShowOverLockscreen(mIntent, mCurrentUserId)).thenReturn(
+                true);
+
+        clickListenerCaptor.getValue().onClick(mView);
+        verify(mActivityStarter).startActivity(mIntent, true, null, true);
+    }
+
+    /**
+     * Ensures clicking media entry chip opens media when flag is set.
+     */
+    @Test
+    public void testClickToOpenMediaDismissingLockscreen() {
+        when(mFeatureFlags.isEnabled(DREAM_MEDIA_TAP_TO_OPEN)).thenReturn(true);
+
+        when(mMediaCarouselController.getCurrentVisibleMediaContentIntent()).thenReturn(
+                mPendingIntent);
+        when(mKeyguardStateController.isShowing()).thenReturn(true);
+        when(mPendingIntent.getIntent()).thenReturn(mIntent);
+        when(mLockscreenUserManager.getCurrentUserId()).thenReturn(mCurrentUserId);
+
+        final DreamMediaEntryComplication.DreamMediaEntryViewController viewController =
+                new DreamMediaEntryComplication.DreamMediaEntryViewController(
+                        mView,
+                        mDreamOverlayStateController,
+                        mMediaComplication,
+                        mMediaCarouselController,
+                        mActivityStarter,
+                        mActivityIntentHelper,
+                        mKeyguardStateController,
+                        mLockscreenUserManager,
+                        mFeatureFlags);
+        viewController.onViewAttached();
+
+        final ArgumentCaptor<View.OnClickListener> clickListenerCaptor =
+                ArgumentCaptor.forClass(View.OnClickListener.class);
+        verify(mView).setOnClickListener(clickListenerCaptor.capture());
+
+        when(mActivityIntentHelper.wouldShowOverLockscreen(mIntent, mCurrentUserId)).thenReturn(
+                false);
+
+        clickListenerCaptor.getValue().onClick(mView);
+        verify(mActivityStarter).postStartActivityDismissingKeyguard(mPendingIntent, null);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
index 5dd1cfc..e3e3b74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.media
 
+import android.app.PendingIntent
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper
 import androidx.test.filters.SmallTest
@@ -43,6 +44,7 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.Captor
 import org.mockito.Mock
+import org.mockito.Mockito.mock
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.Mockito.`when` as whenever
@@ -366,7 +368,7 @@
                 playerIndex,
                 mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
         )
-        assertEquals( playerIndex, 0)
+        assertEquals(playerIndex, 0)
 
         // Replaying the same media player one more time.
         // And check that the card stays in its position.
@@ -402,4 +404,44 @@
         visualStabilityCallback.value.onReorderingAllowed()
         assertEquals(true, result)
     }
+
+    @Test
+    fun testGetCurrentVisibleMediaContentIntent() {
+        val clickIntent1 = mock(PendingIntent::class.java)
+        val player1 = Triple("player1",
+                DATA.copy(clickIntent = clickIntent1),
+                1000L)
+        clock.setCurrentTimeMillis(player1.third)
+        MediaPlayerData.addMediaPlayer(player1.first,
+                player1.second.copy(notificationKey = player1.first),
+                panel, clock, isSsReactivated = false)
+
+        assertEquals(mediaCarouselController.getCurrentVisibleMediaContentIntent(), clickIntent1)
+
+        val clickIntent2 = mock(PendingIntent::class.java)
+        val player2 = Triple("player2",
+                DATA.copy(clickIntent = clickIntent2),
+                2000L)
+        clock.setCurrentTimeMillis(player2.third)
+        MediaPlayerData.addMediaPlayer(player2.first,
+                player2.second.copy(notificationKey = player2.first),
+                panel, clock, isSsReactivated = false)
+
+        // mediaCarouselScrollHandler.visibleMediaIndex is unchanged (= 0), and the new player is
+        // added to the front because it was active more recently.
+        assertEquals(mediaCarouselController.getCurrentVisibleMediaContentIntent(), clickIntent2)
+
+        val clickIntent3 = mock(PendingIntent::class.java)
+        val player3 = Triple("player3",
+                DATA.copy(clickIntent = clickIntent3),
+                500L)
+        clock.setCurrentTimeMillis(player3.third)
+        MediaPlayerData.addMediaPlayer(player3.first,
+                player3.second.copy(notificationKey = player3.first),
+                panel, clock, isSsReactivated = false)
+
+        // mediaCarouselScrollHandler.visibleMediaIndex is unchanged (= 0), and the new player is
+        // added to the end because it was active less recently.
+        assertEquals(mediaCarouselController.getCurrentVisibleMediaContentIntent(), clickIntent2)
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
index 0bfc034..2f52950 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.media.dream;
 
-import static com.android.systemui.flags.Flags.MEDIA_DREAM_COMPLICATION;
+import static com.android.systemui.flags.Flags.DREAM_MEDIA_COMPLICATION;
 
 import static org.mockito.AdditionalMatchers.not;
 import static org.mockito.ArgumentMatchers.any;
@@ -68,7 +68,7 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
 
-        when(mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)).thenReturn(true);
+        when(mFeatureFlags.isEnabled(DREAM_MEDIA_COMPLICATION)).thenReturn(true);
     }
 
     @Test
@@ -137,7 +137,7 @@
 
     @Test
     public void testOnMediaDataLoaded_mediaComplicationDisabled_doesNotAddComplication() {
-        when(mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)).thenReturn(false);
+        when(mFeatureFlags.isEnabled(DREAM_MEDIA_COMPLICATION)).thenReturn(false);
 
         final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
                 mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags);