Added new interpolators for preview items in large folders.

With larger folders, we want the preview items to reach their final positions faster
(when opening) and later (when closing) so that they appear aligned with the rest of
the folder items when they are both visible.

Bug: 35064148
Change-Id: I170ac2db36a3a20ebe5505711ea59e625050bc1b
diff --git a/res/interpolator/folder_preview_item_closing_interpolator.xml b/res/interpolator/folder_preview_item_closing_interpolator.xml
new file mode 100644
index 0000000..1d77081
--- /dev/null
+++ b/res/interpolator/folder_preview_item_closing_interpolator.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2017, 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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:controlX1="1"
+    android:controlY1="0"
+    android:controlX2="1"
+    android:controlY2="0"/>
diff --git a/res/interpolator/folder_preview_item_opening_interpolator.xml b/res/interpolator/folder_preview_item_opening_interpolator.xml
new file mode 100644
index 0000000..dcf0157
--- /dev/null
+++ b/res/interpolator/folder_preview_item_opening_interpolator.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2017, 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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:controlX1="0"
+    android:controlY1="1"
+    android:controlX2="0"
+    android:controlY2="1"/>
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 9ce1c57..6ce572d 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -65,6 +65,8 @@
     private Animator mRevealAnimator;
     private final TimeInterpolator mOpeningInterpolator;
     private final TimeInterpolator mClosingInterpolator;
+    private final TimeInterpolator mPreviewItemOpeningInterpolator;
+    private final TimeInterpolator mPreviewItemClosingInterpolator;
 
     private final FolderIcon.PreviewItemDrawingParams mTmpParams =
             new FolderIcon.PreviewItemDrawingParams(0, 0, 0, 0);
@@ -115,6 +117,10 @@
                 R.interpolator.folder_opening_interpolator);
         mClosingInterpolator = AnimationUtils.loadInterpolator(mContext,
                 R.interpolator.folder_closing_interpolator);
+        mPreviewItemOpeningInterpolator = AnimationUtils.loadInterpolator(mContext,
+                R.interpolator.folder_preview_item_opening_interpolator);
+        mPreviewItemClosingInterpolator = AnimationUtils.loadInterpolator(mContext,
+                R.interpolator.folder_preview_item_closing_interpolator);
     }
 
     public AnimatorSet getOpeningAnimator() {
@@ -122,7 +128,6 @@
         mFolder.setPivotY(0);
 
         AnimatorSet a = getAnimatorSet(true /* isOpening */);
-        a.setInterpolator(mOpeningInterpolator);
         a.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
@@ -134,7 +139,6 @@
 
     public AnimatorSet getClosingAnimator() {
         AnimatorSet a = getAnimatorSet(false /* isOpening */);
-        a.setInterpolator(mClosingInterpolator);
         return a;
     }
 
@@ -242,6 +246,12 @@
             }
         });
 
+        // We set the interpolator on all current child animators here, because the preview item
+        // animators may use a different interpolator.
+        for (Animator animator : a.getChildAnimations()) {
+            animator.setInterpolator(isOpening ? mOpeningInterpolator : mClosingInterpolator);
+        }
+
         addPreviewItemAnimatorsToSet(a, isOpening, folderScale, nudgeOffsetX);
         return a;
     }
@@ -269,6 +279,8 @@
         final List<BubbleTextView> itemsInPreview = mFolderIcon.getItemsToDisplay();
         final int numItemsInPreview = itemsInPreview.size();
 
+        TimeInterpolator previewItemInterpolator = getPreviewItemInterpolator(isOpening);
+
         ShortcutAndWidgetContainer cwc = mContent.getPageAt(0).getShortcutsAndWidgets();
         for (int i = 0; i < numItemsInPreview; ++i) {
             final BubbleTextView btv = itemsInPreview.get(i);
@@ -305,16 +317,19 @@
             ObjectAnimator translationX = isOpening
                     ? ObjectAnimator.ofFloat(btv, View.TRANSLATION_X, xDistance, 0)
                     : ObjectAnimator.ofFloat(btv, View.TRANSLATION_X, 0, xDistance);
+            translationX.setInterpolator(previewItemInterpolator);
             animatorSet.play(translationX);
 
             ObjectAnimator translationY = isOpening
                     ? ObjectAnimator.ofFloat(btv, View.TRANSLATION_Y, yDistance, 0)
                     : ObjectAnimator.ofFloat(btv, View.TRANSLATION_Y, 0, yDistance);
+            translationY.setInterpolator(previewItemInterpolator);
             animatorSet.play(translationY);
 
             ObjectAnimator scaleAnimator = isOpening
                     ? ObjectAnimator.ofFloat(btv, SCALE_PROPERTY, initialScale, finalScale)
                     : ObjectAnimator.ofFloat(btv, SCALE_PROPERTY, finalScale, initialScale);
+            scaleAnimator.setInterpolator(previewItemInterpolator);
             animatorSet.play(scaleAnimator);
 
             animatorSet.addListener(new AnimatorListenerAdapter() {
@@ -329,4 +344,14 @@
             });
         }
     }
+
+    private TimeInterpolator getPreviewItemInterpolator(boolean isOpening) {
+        if (mFolder.getItemCount() > FolderIcon.NUM_ITEMS_IN_PREVIEW) {
+            // With larger folders, we want the preview items to reach their final positions faster
+            // (when opening) and later (when closing) so that they appear aligned with the rest of
+            // the folder items when they are both visible.
+            return isOpening ? mPreviewItemOpeningInterpolator : mPreviewItemClosingInterpolator;
+        }
+        return isOpening ? mOpeningInterpolator : mClosingInterpolator;
+    }
 }