Merge cherrypicks of ['googleplex-android-review.googlesource.com/27902855', 'googleplex-android-review.googlesource.com/27951519', 'googleplex-android-review.googlesource.com/27976521'] into 24Q3-release.

Change-Id: I700dccc620c1f24e25094d8bd240156d4459e877
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index fd141c3..d18c86e 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -492,18 +492,8 @@
                 TaskContainer taskContainer) {
             boolean isTablet = container.getDeviceProfile().isTablet;
             boolean isGridOnlyOverview = isTablet && Flags.enableGridOnlyOverview();
-            // Extra conditions if it's not grid-only overview
             if (!isGridOnlyOverview) {
-                RecentsOrientedState orientedState = taskContainer.getTaskView().getOrientedState();
-                boolean isFakeLandscape = !orientedState.isRecentsActivityRotationAllowed()
-                        && orientedState.getTouchRotation() != ROTATION_0;
-                if (!isFakeLandscape) {
-                    return null;
-                }
-                // Disallow "Select" when swiping up from landscape due to rotated thumbnail.
-                if (orientedState.getDisplayRotation() != ROTATION_0) {
-                    return null;
-                }
+                return null;
             }
 
             SystemShortcut modalStateSystemShortcut =
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 4f802c9..6798676 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -31,6 +31,7 @@
 import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.app.animation.Interpolators.OVERSHOOT_0_75;
 import static com.android.app.animation.Interpolators.clampToProgress;
+import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
 import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
 import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
 import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
@@ -130,6 +131,7 @@
 import androidx.core.graphics.ColorUtils;
 
 import com.android.internal.jank.Cuj;
+import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Flags;
@@ -2688,6 +2690,7 @@
     }
 
     private void animateRotation(int newRotation) {
+        AbstractFloatingView.closeAllOpenViewsExcept(mContainer, false, TYPE_REBIND_SAFE);
         AnimatorSet pa = setRecentsChangedOrientation(true);
         pa.addListener(AnimatorListeners.forSuccessCallback(() -> {
             setLayoutRotation(newRotation, mOrientationState.getDisplayRotation());
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index dc6968c..312c6f4 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -209,7 +209,7 @@
                 mApp.getContext().getContentResolver(),
                 "launcher_broadcast_installed_apps",
                 /* def= */ 0);
-        if (launcherBroadcastInstalledApps == 1) {
+        if (launcherBroadcastInstalledApps == 1 && mIsRestoreFromBackup) {
             List<FirstScreenBroadcastModel> broadcastModels =
                     FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
                             mPmHelper,
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index 28a001f..d16674c 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -1,10 +1,13 @@
 package com.android.launcher3.model
 
 import android.appwidget.AppWidgetManager
+import android.content.Intent
 import android.os.UserHandle
 import android.platform.test.flag.junit.SetFlagsRule
+import android.provider.Settings
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.dx.mockito.inline.extended.ExtendedMockito
 import com.android.launcher3.Flags
 import com.android.launcher3.InvariantDeviceProfile
 import com.android.launcher3.LauncherAppState
@@ -14,6 +17,7 @@
 import com.android.launcher3.icons.cache.CachingLogic
 import com.android.launcher3.icons.cache.IconCacheUpdateHandler
 import com.android.launcher3.pm.UserCache
+import com.android.launcher3.provider.RestoreDbTask
 import com.android.launcher3.ui.TestViewHelpers
 import com.android.launcher3.util.Executors.MODEL_EXECUTOR
 import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
@@ -21,21 +25,30 @@
 import com.android.launcher3.util.UserIconInfo
 import com.google.common.truth.Truth
 import java.util.concurrent.CountDownLatch
+import junit.framework.Assert.assertEquals
 import org.junit.After
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers.any
 import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyList
+import org.mockito.ArgumentMatchers.anyMap
 import org.mockito.Mock
 import org.mockito.Mockito
 import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
+import org.mockito.MockitoSession
 import org.mockito.Spy
+import org.mockito.kotlin.anyOrNull
 import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+import org.mockito.quality.Strictness
 
 private const val INSERTION_STATEMENT_FILE = "databases/workspace_items.sql"
 
@@ -43,6 +56,20 @@
 @RunWith(AndroidJUnit4::class)
 class LoaderTaskTest {
     private var context = SandboxModelContext()
+    private val expectedBroadcastModel =
+        FirstScreenBroadcastModel(
+            installerPackage = "installerPackage",
+            pendingCollectionItems = mutableSetOf("pendingCollectionItem"),
+            pendingWidgetItems = mutableSetOf("pendingWidgetItem"),
+            pendingHotseatItems = mutableSetOf("pendingHotseatItem"),
+            pendingWorkspaceItems = mutableSetOf("pendingWorkspaceItem"),
+            installedHotseatItems = mutableSetOf("installedHotseatItem"),
+            installedWorkspaceItems = mutableSetOf("installedWorkspaceItem"),
+            firstScreenInstalledWidgets = mutableSetOf("installedFirstScreenWidget"),
+            secondaryScreenInstalledWidgets = mutableSetOf("installedSecondaryScreenWidget")
+        )
+    private lateinit var mockitoSession: MockitoSession
+
     @Mock private lateinit var app: LauncherAppState
     @Mock private lateinit var bgAllAppsList: AllAppsList
     @Mock private lateinit var modelDelegate: ModelDelegate
@@ -61,7 +88,11 @@
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-
+        mockitoSession =
+            ExtendedMockito.mockitoSession()
+                .strictness(Strictness.LENIENT)
+                .mockStatic(FirstScreenBroadcastHelper::class.java)
+                .startMocking()
         val idp =
             InvariantDeviceProfile().apply {
                 numRows = 5
@@ -90,6 +121,7 @@
     @After
     fun tearDown() {
         context.onDestroy()
+        mockitoSession.finishMocking()
     }
 
     @Test
@@ -166,6 +198,141 @@
             verify(bgAllAppsList, Mockito.never())
                 .setFlags(BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED, true)
         }
+
+    @Test
+    fun `When launcher_broadcast_installed_apps and is restore then send installed item broadcast`() {
+        // Given
+        val spyContext = spy(context)
+        `when`(app.context).thenReturn(spyContext)
+        whenever(
+                FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
+                    anyOrNull(),
+                    anyList(),
+                    anyMap(),
+                    anyList()
+                )
+            )
+            .thenReturn(listOf(expectedBroadcastModel))
+
+        whenever(
+                FirstScreenBroadcastHelper.sendBroadcastsForModels(
+                    spyContext,
+                    listOf(expectedBroadcastModel)
+                )
+            )
+            .thenCallRealMethod()
+
+        Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 1)
+        RestoreDbTask.setPending(spyContext)
+
+        // When
+        LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+            .runSyncOnBackgroundThread()
+
+        // Then
+        val argumentCaptor = ArgumentCaptor.forClass(Intent::class.java)
+        verify(spyContext).sendBroadcast(argumentCaptor.capture())
+        val actualBroadcastIntent = argumentCaptor.value
+        assertEquals(expectedBroadcastModel.installerPackage, actualBroadcastIntent.`package`)
+        assertEquals(
+            ArrayList(expectedBroadcastModel.installedWorkspaceItems),
+            actualBroadcastIntent.getStringArrayListExtra("workspaceInstalledItems")
+        )
+        assertEquals(
+            ArrayList(expectedBroadcastModel.installedHotseatItems),
+            actualBroadcastIntent.getStringArrayListExtra("hotseatInstalledItems")
+        )
+        assertEquals(
+            ArrayList(
+                expectedBroadcastModel.firstScreenInstalledWidgets +
+                    expectedBroadcastModel.secondaryScreenInstalledWidgets
+            ),
+            actualBroadcastIntent.getStringArrayListExtra("widgetInstalledItems")
+        )
+        assertEquals(
+            ArrayList(expectedBroadcastModel.pendingCollectionItems),
+            actualBroadcastIntent.getStringArrayListExtra("folderItem")
+        )
+        assertEquals(
+            ArrayList(expectedBroadcastModel.pendingWorkspaceItems),
+            actualBroadcastIntent.getStringArrayListExtra("workspaceItem")
+        )
+        assertEquals(
+            ArrayList(expectedBroadcastModel.pendingHotseatItems),
+            actualBroadcastIntent.getStringArrayListExtra("hotseatItem")
+        )
+        assertEquals(
+            ArrayList(expectedBroadcastModel.pendingWidgetItems),
+            actualBroadcastIntent.getStringArrayListExtra("widgetItem")
+        )
+    }
+
+    @Test
+    fun `When not a restore then installed item broadcast not sent`() {
+        // Given
+        val spyContext = spy(context)
+        `when`(app.context).thenReturn(spyContext)
+        whenever(
+                FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
+                    anyOrNull(),
+                    anyList(),
+                    anyMap(),
+                    anyList()
+                )
+            )
+            .thenReturn(listOf(expectedBroadcastModel))
+
+        whenever(
+                FirstScreenBroadcastHelper.sendBroadcastsForModels(
+                    spyContext,
+                    listOf(expectedBroadcastModel)
+                )
+            )
+            .thenCallRealMethod()
+
+        Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 1)
+
+        // When
+        LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+            .runSyncOnBackgroundThread()
+
+        // Then
+        verify(spyContext, times(0)).sendBroadcast(any(Intent::class.java))
+    }
+
+    @Test
+    fun `When launcher_broadcast_installed_apps false then installed item broadcast not sent`() {
+        // Given
+        val spyContext = spy(context)
+        `when`(app.context).thenReturn(spyContext)
+        whenever(
+                FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
+                    anyOrNull(),
+                    anyList(),
+                    anyMap(),
+                    anyList()
+                )
+            )
+            .thenReturn(listOf(expectedBroadcastModel))
+
+        whenever(
+                FirstScreenBroadcastHelper.sendBroadcastsForModels(
+                    spyContext,
+                    listOf(expectedBroadcastModel)
+                )
+            )
+            .thenCallRealMethod()
+
+        Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 0)
+        RestoreDbTask.setPending(spyContext)
+
+        // When
+        LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+            .runSyncOnBackgroundThread()
+
+        // Then
+        verify(spyContext, times(0)).sendBroadcast(any(Intent::class.java))
+    }
 }
 
 private fun LoaderTask.runSyncOnBackgroundThread() {