Merge "Making caret visibility part of state definition" into ub-launcher3-edmonton
diff --git a/proguard.flags b/proguard.flags
index e9f6db4..555d13e 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -120,6 +120,12 @@
   *;
 }
 
+# Discovery bounce animation
+-keep class com.android.launcher3.allapps.DiscoveryBounce$VerticalProgressWrapper {
+  public void setProgress(float);
+  public float getProgress();
+}
+
 # BUG(70852369): Surpress additional warnings after changing from Proguard to R8
 -dontwarn android.app.**
 -dontwarn android.view.**
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 429f3a2..f163872 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -13,9 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.quickstep.views.TaskView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.quickstep.views.TaskView
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:focusable="false"
     android:elevation="4dp">
 
     <com.android.quickstep.views.TaskThumbnailView
@@ -29,5 +31,6 @@
         android:layout_width="@dimen/task_thumbnail_icon_size"
         android:layout_height="@dimen/task_thumbnail_icon_size"
         android:importantForAccessibility="no"
+        android:focusable="false"
         android:layout_gravity="top|center_horizontal" />
 </com.android.quickstep.views.TaskView>
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index d5c43a0..25e3dc6 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -19,6 +19,7 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
 
 import android.content.Context;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.util.AttributeSet;
@@ -43,4 +44,12 @@
         }
         return res;
     }
+
+    @Override
+    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+        super.onFocusChanged(focused, direction, previouslyFocusedRect);
+        if (focused) {
+            mRecentsView.revealClearAllButton();
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 65b53fe..ae8ebbe 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -41,6 +41,7 @@
 import android.os.Build;
 import android.os.Handler;
 import android.os.UserHandle;
+import android.support.annotation.Nullable;
 import android.text.Layout;
 import android.text.StaticLayout;
 import android.text.TextPaint;
@@ -582,6 +583,11 @@
      * and unloads the associated task data for tasks that are no longer visible.
      */
     public void loadVisibleTaskData() {
+        if (!mOverviewStateEnabled) {
+            // Skip loading visible task data if we've already left the overview state
+            return;
+        }
+
         RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
         int centerPageIndex = getPageNearestToCenterOfScreen();
         int lower = Math.max(0, centerPageIndex - 2);
@@ -968,6 +974,13 @@
         if (event.getAction() == KeyEvent.ACTION_DOWN) {
             switch (event.getKeyCode()) {
                 case KeyEvent.KEYCODE_TAB:
+                    if (!event.isAltPressed() &&
+                            getNextPage() ==
+                                    (event.isShiftPressed() ? 0 : getChildCount() - 1)) {
+                        // If not Alt-Tab navigation, don't loop forever in the carousel and leave
+                        // it once we reached the end.
+                        return false;
+                    }
                     snapToPageRelative(event.isShiftPressed() ? -1 : 1);
                     return true;
                 case KeyEvent.KEYCODE_DPAD_RIGHT:
@@ -993,6 +1006,22 @@
         return super.dispatchKeyEvent(event);
     }
 
+    @Override
+    protected void onFocusChanged(boolean gainFocus, int direction,
+            @Nullable Rect previouslyFocusedRect) {
+        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
+        if (gainFocus && getChildCount() > 0) {
+            switch (direction) {
+                case FOCUS_FORWARD:
+                    setCurrentPage(0);
+                    break;
+                case FOCUS_BACKWARD:
+                    setCurrentPage(getChildCount() - 1);
+                    break;
+            }
+        }
+    }
+
     public void snapToTaskAfterNext() {
         snapToPageRelative(1);
     }
@@ -1304,6 +1333,7 @@
     }
 
     public void revealClearAllButton() {
+        setCurrentPage(getChildCount() - 1); // Loads tasks info if needed.
         scrollTo(mIsRtl ? 0 : computeMaxScrollX(), 0);
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
index 429432b..06e2e89 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
@@ -25,10 +25,13 @@
 import android.util.FloatProperty;
 import android.view.Gravity;
 import android.view.MotionEvent;
+import android.view.View;
 
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.R;
 
+import java.util.ArrayList;
+
 public class RecentsViewContainer extends InsettableFrameLayout {
     public static final FloatProperty<RecentsViewContainer> CONTENT_ALPHA =
             new FloatProperty<RecentsViewContainer>("contentAlpha") {
@@ -104,4 +107,11 @@
         mRecentsView.setContentAlpha(alpha);
         setVisibility(alpha > 0 ? VISIBLE : GONE);
     }
+
+    @Override
+    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
+        // Carousel is first in tab order.
+        views.add(mRecentsView);
+        views.add(mClearAllButton);
+    }
 }
\ No newline at end of file
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index 5e7b117..02d793e 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -23,8 +23,7 @@
     android:layout_height="match_parent"
     android:clipChildren="true"
     android:clipToPadding="false"
-    android:focusable="true"
-    android:focusableInTouchMode="true"
+    android:focusable="false"
     android:saveEnabled="false" >
 
     <include layout="@layout/all_apps_rv_layout" />
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index e1cd06a..a0a79c8 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -24,14 +24,9 @@
 import android.animation.Animator;
 import android.animation.AnimatorInflater;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.Keyframe;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.TimeInterpolator;
 import android.app.ActivityManager;
 import android.os.Handler;
 import android.view.MotionEvent;
-import android.view.animation.PathInterpolator;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.Launcher;
@@ -52,21 +47,21 @@
     private final Launcher mLauncher;
     private final Animator mDiscoBounceAnimation;
 
-    public DiscoveryBounce(Launcher launcher, Animator animator) {
+    public DiscoveryBounce(Launcher launcher, float delta) {
         super(launcher, null);
         mLauncher = launcher;
-
-        mDiscoBounceAnimation = animator;
         AllAppsTransitionController controller = mLauncher.getAllAppsController();
-        mDiscoBounceAnimation.setTarget(controller);
-        mDiscoBounceAnimation.addListener(controller.getProgressAnimatorListener());
 
+        mDiscoBounceAnimation =
+                AnimatorInflater.loadAnimator(launcher, R.animator.discovery_bounce);
+        mDiscoBounceAnimation.setTarget(new VerticalProgressWrapper(controller, delta));
         mDiscoBounceAnimation.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 handleClose(false);
             }
         });
+        mDiscoBounceAnimation.addListener(controller.getProgressAnimatorListener());
     }
 
     @Override
@@ -102,6 +97,9 @@
         if (mIsOpen) {
             mIsOpen = false;
             mLauncher.getDragLayer().removeView(this);
+            // Reset the all-apps progress to what ever it was previously.
+            mLauncher.getAllAppsController().setProgress(mLauncher.getStateManager()
+                    .getState().getVerticalProgress(mLauncher));
         }
     }
 
@@ -115,6 +113,12 @@
         return (type & TYPE_ON_BOARD_POPUP) != 0;
     }
 
+    private void show(int containerType) {
+        mIsOpen = true;
+        mLauncher.getDragLayer().addView(this);
+        mLauncher.getUserEventDispatcher().logActionBounceTip(containerType);
+    }
+
     public static void showForHomeIfNeeded(Launcher launcher) {
         showForHomeIfNeeded(launcher, true);
     }
@@ -133,11 +137,7 @@
             return;
         }
 
-        DiscoveryBounce view = new DiscoveryBounce(launcher,
-                AnimatorInflater.loadAnimator(launcher, R.animator.discovery_bounce));
-        view.mIsOpen = true;
-        launcher.getDragLayer().addView(view);
-        launcher.getUserEventDispatcher().logActionBounceTip(HOTSEAT);
+        new DiscoveryBounce(launcher, 0).show(HOTSEAT);
     }
 
     public static void showForOverviewIfNeeded(Launcher launcher) {
@@ -164,26 +164,29 @@
             return;
         }
 
-        float verticalProgress = OVERVIEW.getVerticalProgress(launcher);
+        new DiscoveryBounce(launcher, (1 - OVERVIEW.getVerticalProgress(launcher)))
+                .show(PREDICTION);
+    }
 
-        TimeInterpolator pathInterpolator = new PathInterpolator(0.35f, 0, 0.5f, 1);
-        Keyframe keyframe3 = Keyframe.ofFloat(0.423f, verticalProgress - (1 - 0.9738f));
-        keyframe3.setInterpolator(pathInterpolator);
-        Keyframe keyframe4 = Keyframe.ofFloat(0.754f, verticalProgress);
-        keyframe4.setInterpolator(pathInterpolator);
+    /**
+     * A wrapper around {@link AllAppsTransitionController} allowing a fixed shift in the value.
+     */
+    public static class VerticalProgressWrapper {
 
-        PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe("progress",
-                Keyframe.ofFloat(0, verticalProgress),
-                Keyframe.ofFloat(0.246f, verticalProgress), keyframe3, keyframe4,
-                Keyframe.ofFloat(1f, verticalProgress));
-        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(null,
-                new PropertyValuesHolder[]{propertyValuesHolder});
-        animator.setDuration(2166);
-        animator.setRepeatCount(5);
+        private final float mDelta;
+        private final AllAppsTransitionController mController;
 
-        DiscoveryBounce view = new DiscoveryBounce(launcher, animator);
-        view.mIsOpen = true;
-        launcher.getDragLayer().addView(view);
-        launcher.getUserEventDispatcher().logActionBounceTip(PREDICTION);
+        private VerticalProgressWrapper(AllAppsTransitionController controller, float delta) {
+            mController = controller;
+            mDelta = delta;
+        }
+
+        public float getProgress() {
+            return mController.getProgress() + mDelta;
+        }
+
+        public void setProgress(float progress) {
+            mController.setProgress(progress - mDelta);
+        }
     }
 }
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 3b5585b..f020d2d 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -360,16 +360,18 @@
                 .getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
         IconCache cache = LauncherAppState.getInstance(mContext).getIconCache();
 
-        Bitmap unbadgedBitmap = null;
+        final Bitmap unbadgedBitmap;
         if (unbadgedDrawable != null) {
             unbadgedBitmap = createScaledBitmapWithoutShadow(unbadgedDrawable, 0);
         } else {
             if (fallbackIconProvider != null) {
-                unbadgedBitmap = fallbackIconProvider.get();
+                // Fallback icons are already badged and with appropriate shadow
+                Bitmap fullIcon = fallbackIconProvider.get();
+                if (fullIcon != null) {
+                    return createIconBitmap(fullIcon);
+                }
             }
-            if (unbadgedBitmap == null) {
-                unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle()).icon;
-            }
+            unbadgedBitmap = cache.getDefaultIcon(Process.myUserHandle()).icon;
         }
 
         BitmapInfo result = new BitmapInfo();
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index d01da43..6e3ef07 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -134,6 +134,7 @@
         ViewCompat.setAccessibilityDelegate(this, mAccessibilityHelper);
 
         mAM = (AccessibilityManager) context.getSystemService(ACCESSIBILITY_SERVICE);
+        setFocusable(false);
     }
 
     @NonNull