Merge "Support sysUiStatusNavFlags for refactored TTV" into main
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 9df0576..fab7975 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -801,7 +801,6 @@
                 listener);
     }
 
-    // TODO: (b/280605790) animate it
     @Override
     public void addView(View child, int index, ViewGroup.LayoutParams params) {
         super.addView(child, index, params);
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
deleted file mode 100644
index bb4a7ec..0000000
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.views;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.views.ActivityContext;
-import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
-import com.android.quickstep.util.RecentsOrientedState;
-
-/**
- * A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
- * when the drawable changes.
- */
-public class IconView extends View implements TaskViewIcon {
-    private static final int NUM_ALPHA_CHANNELS = 2;
-    private static final int INDEX_CONTENT_ALPHA = 0;
-    private static final int INDEX_MODAL_ALPHA = 1;
-
-    private final MultiValueAlpha mMultiValueAlpha;
-
-    @Nullable
-    private Drawable mDrawable;
-    private int mDrawableWidth, mDrawableHeight;
-
-    public IconView(Context context) {
-        this(context, null);
-    }
-
-    public IconView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public IconView(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public IconView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        mMultiValueAlpha = new MultiValueAlpha(this, NUM_ALPHA_CHANNELS);
-        mMultiValueAlpha.setUpdateVisibility(/* updateVisibility= */ true);
-    }
-
-    /**
-     * Sets a {@link Drawable} to be displayed.
-     */
-    @Override
-    public void setDrawable(@Nullable Drawable d) {
-        if (mDrawable != null) {
-            mDrawable.setCallback(null);
-        }
-        mDrawable = d;
-        if (mDrawable != null) {
-            mDrawable.setCallback(this);
-            setDrawableSizeInternal(getWidth(), getHeight());
-        }
-        invalidate();
-    }
-
-    /**
-     * Sets the size of the icon drawable.
-     */
-    @Override
-    public void setDrawableSize(int iconWidth, int iconHeight) {
-        mDrawableWidth = iconWidth;
-        mDrawableHeight = iconHeight;
-        if (mDrawable != null) {
-            setDrawableSizeInternal(getWidth(), getHeight());
-        }
-    }
-
-    private void setDrawableSizeInternal(int selfWidth, int selfHeight) {
-        Rect selfRect = new Rect(0, 0, selfWidth, selfHeight);
-        Rect drawableRect = new Rect();
-        Gravity.apply(Gravity.CENTER, mDrawableWidth, mDrawableHeight, selfRect, drawableRect);
-        mDrawable.setBounds(drawableRect);
-    }
-
-    @Override
-    @Nullable
-    public Drawable getDrawable() {
-        return mDrawable;
-    }
-
-    @Override
-    public int getDrawableWidth() {
-        return mDrawableWidth;
-    }
-
-    @Override
-    public int getDrawableHeight() {
-        return mDrawableHeight;
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-        if (mDrawable != null) {
-            setDrawableSizeInternal(w, h);
-        }
-    }
-
-    @Override
-    protected boolean verifyDrawable(Drawable who) {
-        return super.verifyDrawable(who) || who == mDrawable;
-    }
-
-    @Override
-    protected void drawableStateChanged() {
-        super.drawableStateChanged();
-
-        final Drawable drawable = mDrawable;
-        if (drawable != null && drawable.isStateful()
-                && drawable.setState(getDrawableState())) {
-            invalidateDrawable(drawable);
-        }
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mDrawable != null) {
-            mDrawable.draw(canvas);
-        }
-    }
-
-    @Override
-    public boolean hasOverlappingRendering() {
-        return false;
-    }
-
-    @Override
-    public void setContentAlpha(float alpha) {
-        mMultiValueAlpha.get(INDEX_CONTENT_ALPHA).setValue(alpha);
-    }
-
-    @Override
-    public void setModalAlpha(float alpha) {
-        mMultiValueAlpha.get(INDEX_MODAL_ALPHA).setValue(alpha);
-    }
-
-    /**
-     * Set the tint color of the icon, useful for scrimming or dimming.
-     *
-     * @param color to blend in.
-     * @param amount [0,1] 0 no tint, 1 full tint
-     */
-    @Override
-    public void setIconColorTint(int color, float amount) {
-        if (mDrawable != null) {
-            mDrawable.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount));
-        }
-    }
-
-    @Override
-    public void setIconOrientation(RecentsOrientedState orientationState, boolean isGridTask) {
-        RecentsPagedOrientationHandler orientationHandler =
-                orientationState.getOrientationHandler();
-        boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
-        DeviceProfile deviceProfile =
-                ActivityContext.lookupContext(getContext()).getDeviceProfile();
-
-        FrameLayout.LayoutParams iconParams = (FrameLayout.LayoutParams) getLayoutParams();
-
-        int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
-        int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
-        int taskMargin = deviceProfile.overviewTaskMarginPx;
-
-        orientationHandler.setTaskIconParams(iconParams, taskMargin, taskIconHeight,
-                thumbnailTopMargin, isRtl);
-        iconParams.width = iconParams.height = taskIconHeight;
-        setLayoutParams(iconParams);
-
-        setRotation(orientationHandler.getDegreesRotated());
-        int iconDrawableSize = isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
-                : deviceProfile.overviewTaskIconDrawableSizePx;
-        setDrawableSize(iconDrawableSize, iconDrawableSize);
-    }
-
-    @Override
-    public View asView() {
-        return this;
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/views/IconView.kt b/quickstep/src/com/android/quickstep/views/IconView.kt
new file mode 100644
index 0000000..583207f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/IconView.kt
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import android.view.Gravity
+import android.view.View
+import android.widget.FrameLayout
+import androidx.core.view.updateLayoutParams
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.Utilities
+import com.android.launcher3.util.MultiValueAlpha
+import com.android.launcher3.views.ActivityContext
+import com.android.quickstep.util.RecentsOrientedState
+
+/**
+ * A view which draws a drawable stretched to fit its size. Unlike ImageView, it avoids relayout
+ * when the drawable changes.
+ */
+class IconView : View, TaskViewIcon {
+    private val multiValueAlpha: MultiValueAlpha = MultiValueAlpha(this, NUM_ALPHA_CHANNELS)
+    private var drawable: Drawable? = null
+    private var drawableWidth = 0
+    private var drawableHeight = 0
+
+    constructor(context: Context) : super(context)
+
+    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+    constructor(
+        context: Context,
+        attrs: AttributeSet?,
+        defStyleAttr: Int,
+    ) : super(context, attrs, defStyleAttr)
+
+    init {
+        multiValueAlpha.setUpdateVisibility(true)
+    }
+
+    /** Sets a [Drawable] to be displayed. */
+    override fun setDrawable(d: Drawable?) {
+        drawable?.callback = null
+
+        drawable = d
+        drawable?.let {
+            it.callback = this
+            setDrawableSizeInternal(width, height)
+        }
+        invalidate()
+    }
+
+    /** Sets the size of the icon drawable. */
+    override fun setDrawableSize(iconWidth: Int, iconHeight: Int) {
+        drawableWidth = iconWidth
+        drawableHeight = iconHeight
+        drawable?.let { setDrawableSizeInternal(width, height) }
+    }
+
+    private fun setDrawableSizeInternal(selfWidth: Int, selfHeight: Int) {
+        val selfRect = Rect(0, 0, selfWidth, selfHeight)
+        val drawableRect = Rect()
+        Gravity.apply(Gravity.CENTER, drawableWidth, drawableHeight, selfRect, drawableRect)
+        drawable?.bounds = drawableRect
+    }
+
+    override fun getDrawable(): Drawable? = drawable
+
+    override fun getDrawableWidth(): Int = drawableWidth
+
+    override fun getDrawableHeight(): Int = drawableHeight
+
+    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
+        super.onSizeChanged(w, h, oldw, oldh)
+        drawable?.let { setDrawableSizeInternal(w, h) }
+    }
+
+    override fun verifyDrawable(who: Drawable): Boolean =
+        super.verifyDrawable(who) || who === drawable
+
+    override fun drawableStateChanged() {
+        super.drawableStateChanged()
+        drawable?.let {
+            if (it.isStateful && it.setState(drawableState)) {
+                invalidateDrawable(it)
+            }
+        }
+    }
+
+    override fun onDraw(canvas: Canvas) {
+        drawable?.draw(canvas)
+    }
+
+    override fun hasOverlappingRendering(): Boolean = false
+
+    override fun setContentAlpha(alpha: Float) {
+        multiValueAlpha[INDEX_CONTENT_ALPHA].setValue(alpha)
+    }
+
+    override fun setModalAlpha(alpha: Float) {
+        multiValueAlpha[INDEX_MODAL_ALPHA].setValue(alpha)
+    }
+
+    /**
+     * Set the tint color of the icon, useful for scrimming or dimming.
+     *
+     * @param color to blend in.
+     * @param amount [0,1] 0 no tint, 1 full tint
+     */
+    override fun setIconColorTint(color: Int, amount: Float) {
+        drawable?.colorFilter = Utilities.makeColorTintingColorFilter(color, amount)
+    }
+
+    override fun setIconOrientation(orientationState: RecentsOrientedState, isGridTask: Boolean) {
+        val orientationHandler = orientationState.orientationHandler
+        val deviceProfile: DeviceProfile =
+            (ActivityContext.lookupContext(context) as ActivityContext).getDeviceProfile()
+        orientationHandler.setTaskIconParams(
+            iconParams = getLayoutParams() as FrameLayout.LayoutParams,
+            taskIconMargin = deviceProfile.overviewTaskMarginPx,
+            taskIconHeight = deviceProfile.overviewTaskIconSizePx,
+            thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx,
+            isRtl = layoutDirection == LAYOUT_DIRECTION_RTL
+        )
+        updateLayoutParams<FrameLayout.LayoutParams> {
+            height = deviceProfile.overviewTaskIconSizePx
+            width = height
+        }
+        setRotation(orientationHandler.degreesRotated)
+        val iconDrawableSize =
+            if (isGridTask) deviceProfile.overviewTaskIconDrawableSizeGridPx
+            else deviceProfile.overviewTaskIconDrawableSizePx
+        setDrawableSize(iconDrawableSize, iconDrawableSize)
+    }
+
+    override fun asView(): View = this
+
+    companion object {
+        private const val NUM_ALPHA_CHANNELS = 2
+        private const val INDEX_CONTENT_ALPHA = 0
+        private const val INDEX_MODAL_ALPHA = 1
+    }
+}
diff --git a/src/com/android/launcher3/util/ShortcutUtil.java b/src/com/android/launcher3/util/ShortcutUtil.java
index 07b7941..aa4f8af 100644
--- a/src/com/android/launcher3/util/ShortcutUtil.java
+++ b/src/com/android/launcher3/util/ShortcutUtil.java
@@ -54,14 +54,6 @@
                 ? ((WorkspaceItemInfo) info).getPersonKeys() : Utilities.EMPTY_STRING_ARRAY;
     }
 
-    /**
-     * Returns true if the item is a deep shortcut.
-     */
-    public static boolean isDeepShortcut(ItemInfo info) {
-        return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
-                && info instanceof WorkspaceItemInfo;
-    }
-
     private static boolean isActive(ItemInfo info) {
         boolean isLoading = info instanceof WorkspaceItemInfo
                 && ((WorkspaceItemInfo) info).hasPromiseIconUi();
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/ShortcutUtilTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/ShortcutUtilTest.kt
new file mode 100644
index 0000000..c43e563
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/ShortcutUtilTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.Utilities
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import org.junit.Assert.assertArrayEquals
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ShortcutUtilTest {
+
+    @Test
+    fun `supportsShortcuts returns true if the item is active and it is an app`() {
+        // A blank workspace item info should be active and should be ITEM_TYPE_APPLICATION
+        val itemInfo = WorkspaceItemInfo()
+        // Action
+        val result = ShortcutUtil.supportsShortcuts(itemInfo)
+        // Verify
+        assertEquals(true, result)
+    }
+
+    @Test
+    fun `supportsDeepShortcuts returns true if the app is active and an app and widgets are enabled`() {
+        // Setup
+        val itemInfo = WorkspaceItemInfo()
+        // Action
+        val result = ShortcutUtil.supportsDeepShortcuts(itemInfo)
+        // Verify
+        assertEquals(true, result)
+    }
+
+    @Test
+    fun `getShortcutIdIfPinnedShortcut returns null if the item is an app`() {
+        // Setup
+        val itemInfo = WorkspaceItemInfo()
+        // Action
+        val result = ShortcutUtil.getShortcutIdIfPinnedShortcut(itemInfo)
+        // Verify
+        assertNull(result)
+    }
+
+    @Test
+    fun `getPersonKeysIfPinnedShortcut returns empty string array if item type is an app`() {
+        // Setup
+        val itemInfo = WorkspaceItemInfo()
+        // Action
+        val result = ShortcutUtil.getPersonKeysIfPinnedShortcut(itemInfo)
+        // Verify
+        assertArrayEquals(Utilities.EMPTY_STRING_ARRAY, result)
+    }
+}