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)