Tune the expand animation interpolation. (1/2)

See b/184726377#comment4 for a video.

Bug: 184726377
Test: Manual
Change-Id: I22981702cc6e3f226c66d9b46827e4b9793b4e11
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index 9248be9..ab9ab83 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -21,7 +21,7 @@
     default_applicable_licenses: ["frameworks_base_packages_SystemUI_license"],
 }
 
-java_library {
+android_library {
 
     name: "SystemUIAnimationLib",
 
@@ -30,9 +30,15 @@
         "src/**/*.kt",
     ],
 
+    resource_dirs: [
+        "res",
+    ],
+
     static_libs: [
         "PluginCoreLib",
         "SystemUI-sensors",
     ],
 
+    manifest: "AndroidManifest.xml",
+
 }
diff --git a/packages/SystemUI/animation/AndroidManifest.xml b/packages/SystemUI/animation/AndroidManifest.xml
new file mode 100644
index 0000000..321cc531
--- /dev/null
+++ b/packages/SystemUI/animation/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.systemui.animation">
+
+
+</manifest>
diff --git a/packages/SystemUI/animation/res/interpolator/launch_animation_interpolator_x.xml b/packages/SystemUI/animation/res/interpolator/launch_animation_interpolator_x.xml
new file mode 100644
index 0000000..620dd48
--- /dev/null
+++ b/packages/SystemUI/animation/res/interpolator/launch_animation_interpolator_x.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2021 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:pathData="M 0, 0 C 0.1217, 0.0462, 0.15, 0.4686, 0.1667, 0.66 C 0.1834, 0.8878, 0.1667, 1, 1, 1" />
\ No newline at end of file
diff --git a/packages/SystemUI/animation/res/interpolator/launch_animation_interpolator_y.xml b/packages/SystemUI/animation/res/interpolator/launch_animation_interpolator_y.xml
new file mode 100644
index 0000000..a268abc
--- /dev/null
+++ b/packages/SystemUI/animation/res/interpolator/launch_animation_interpolator_y.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2021 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:pathData="M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1" />
\ No newline at end of file
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 87f52d5..fc03a9e 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -5,6 +5,7 @@
 import android.animation.ValueAnimator
 import android.app.ActivityManager
 import android.app.PendingIntent
+import android.content.Context
 import android.graphics.Matrix
 import android.graphics.Rect
 import android.os.RemoteException
@@ -16,6 +17,7 @@
 import android.view.SyncRtSurfaceTransactionApplier
 import android.view.View
 import android.view.WindowManager
+import android.view.animation.AnimationUtils
 import android.view.animation.PathInterpolator
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.policy.ScreenDecorationsUtils
@@ -25,11 +27,12 @@
  * A class that allows activities to be started in a seamless way from a view that is transforming
  * nicely into the starting window.
  */
-class ActivityLaunchAnimator {
+class ActivityLaunchAnimator(context: Context) {
     companion object {
-        const val ANIMATION_DURATION = 400L
-        const val ANIMATION_DURATION_FADE_OUT_CONTENT = 67L
-        const val ANIMATION_DURATION_FADE_IN_WINDOW = 200L
+        const val ANIMATION_DURATION = 500L
+        const val ANIMATION_DURATION_FADE_OUT_CONTENT = 183L
+        const val ANIMATION_DURATION_FADE_IN_WINDOW = 216L
+        const val ANIMATION_DELAY_FADE_IN_WINDOW = 166L
         private const val ANIMATION_DURATION_NAV_FADE_IN = 266L
         private const val ANIMATION_DURATION_NAV_FADE_OUT = 133L
         private const val ANIMATION_DELAY_NAV_FADE_IN =
@@ -53,6 +56,14 @@
         }
     }
 
+    /** The interpolator used for the width, height, Y position and corner radius. */
+    private val animationInterpolator = AnimationUtils.loadInterpolator(context,
+            R.interpolator.launch_animation_interpolator_y)
+
+    /** The interpolator used for the X position. */
+    private val animationInterpolatorX = AnimationUtils.loadInterpolator(context,
+            R.interpolator.launch_animation_interpolator_x)
+
     /**
      * Start an intent and animate the opening window. The intent will be started by running
      * [intentStarter], which should use the provided [RemoteAnimationAdapter] and return the launch
@@ -104,6 +115,10 @@
         startIntentWithAnimation(controller) { intentStarter.startPendingIntent(it) }
     }
 
+    /** Create a new animation [Runner] controlled by [controller]. */
+    @VisibleForTesting
+    fun createRunner(controller: Controller): Runner = Runner(controller)
+
     interface PendingIntentStarter {
         /**
          * Start a pending intent using the provided [animationAdapter] and return the launch
@@ -228,7 +243,7 @@
     }
 
     @VisibleForTesting
-    class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() {
+    inner class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() {
         private val rootView = controller.getRootView()
         @PublishedApi internal val context = rootView.context
         private val transactionApplier = SyncRtSurfaceTransactionApplier(rootView)
@@ -308,6 +323,8 @@
             val startBottom = state.bottom
             val startLeft = state.left
             val startRight = state.right
+            val startXCenter = (startLeft + startRight) / 2f
+            val startWidth = startRight - startLeft
 
             val startTopCornerRadius = state.topCornerRadius
             val startBottomCornerRadius = state.bottomCornerRadius
@@ -318,6 +335,8 @@
             val endBottom = windowBounds.bottom
             val endLeft = windowBounds.left
             val endRight = windowBounds.right
+            val endXCenter = (endLeft + endRight) / 2f
+            val endWidth = endRight - endLeft
 
             // TODO(b/184121838): Ensure that we are launching on the same screen.
             val rootViewLocation = rootView.locationOnScreen
@@ -359,14 +378,16 @@
                     return@addUpdateListener
                 }
 
-                // TODO(b/184121838): Use android.R.interpolator.fast_out_extra_slow_in instead.
                 val linearProgress = animation.animatedFraction
-                val progress = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(linearProgress)
+                val progress = animationInterpolator.getInterpolation(linearProgress)
+                val xProgress = animationInterpolatorX.getInterpolation(linearProgress)
+                val xCenter = MathUtils.lerp(startXCenter, endXCenter, xProgress)
+                val halfWidth = lerp(startWidth, endWidth, progress) / 2
 
                 state.top = lerp(startTop, endTop, progress).roundToInt()
                 state.bottom = lerp(startBottom, endBottom, progress).roundToInt()
-                state.left = lerp(startLeft, endLeft, progress).roundToInt()
-                state.right = lerp(startRight, endRight, progress).roundToInt()
+                state.left = (xCenter - halfWidth).roundToInt()
+                state.right = (xCenter + halfWidth).roundToInt()
 
                 state.topCornerRadius = MathUtils.lerp(startTopCornerRadius, endRadius, progress)
                 state.bottomCornerRadius =
@@ -378,7 +399,7 @@
                         1 - Interpolators.ALPHA_OUT.getInterpolation(contentAlphaProgress)
 
                 val backgroundAlphaProgress = getProgress(linearProgress,
-                        ANIMATION_DURATION_FADE_OUT_CONTENT, ANIMATION_DURATION_FADE_IN_WINDOW)
+                        ANIMATION_DELAY_FADE_IN_WINDOW, ANIMATION_DURATION_FADE_IN_WINDOW)
                 state.backgroundAlpha =
                         1 - Interpolators.ALPHA_IN.getInterpolation(backgroundAlphaProgress)