blob: 20e19f45af6adbfc7c9815d040ffbfaad93fc813 [file] [log] [blame]
Jorim Jaggi21c39a72017-10-20 15:47:51 +02001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.wm;
18
Jorim Jaggif5f9e122017-10-24 18:21:09 +020019import static com.android.server.wm.AnimationAdapter.STATUS_BAR_TRANSITION_DURATION;
20
Jorim Jaggi21c39a72017-10-20 15:47:51 +020021import android.graphics.Point;
Jorim Jaggif5f9e122017-10-24 18:21:09 +020022import android.os.SystemClock;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020023import android.view.SurfaceControl;
24import android.view.SurfaceControl.Transaction;
25import android.view.animation.Animation;
Jorim Jaggif5f9e122017-10-24 18:21:09 +020026import android.view.animation.AnimationSet;
27import android.view.animation.Interpolator;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020028import android.view.animation.Transformation;
Jorim Jaggif5f9e122017-10-24 18:21:09 +020029import android.view.animation.TranslateAnimation;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020030
31import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
32
33/**
34 * Animation spec for regular window animations.
35 */
36public class WindowAnimationSpec implements AnimationSpec {
37
38 private Animation mAnimation;
39 private final Point mPosition = new Point();
Jorim Jaggia5e10572017-11-15 14:36:26 +010040 private final ThreadLocal<TmpValues> mThreadLocalTmps = ThreadLocal.withInitial(TmpValues::new);
Jorim Jaggi2e3c31d2017-11-20 19:49:00 +010041 private final boolean mCanSkipFirstFrame;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020042
Jorim Jaggi2e3c31d2017-11-20 19:49:00 +010043 public WindowAnimationSpec(Animation animation, Point position, boolean canSkipFirstFrame) {
Jorim Jaggi21c39a72017-10-20 15:47:51 +020044 mAnimation = animation;
45 mPosition.set(position.x, position.y);
Jorim Jaggi2e3c31d2017-11-20 19:49:00 +010046 mCanSkipFirstFrame = canSkipFirstFrame;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020047 }
48
49 @Override
50 public boolean getDetachWallpaper() {
51 return mAnimation.getDetachWallpaper();
52 }
53
54 @Override
55 public int getBackgroundColor() {
56 return mAnimation.getBackgroundColor();
57 }
58
59 @Override
60 public long getDuration() {
61 return mAnimation.computeDurationHint();
62 }
63
64 @Override
65 public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
Jorim Jaggia5e10572017-11-15 14:36:26 +010066 final TmpValues tmp = mThreadLocalTmps.get();
Jorim Jaggi21c39a72017-10-20 15:47:51 +020067 tmp.transformation.clear();
68 mAnimation.getTransformation(currentPlayTime, tmp.transformation);
69 tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
70 t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
71 t.setAlpha(leash, tmp.transformation.getAlpha());
Jorim Jaggif5f9e122017-10-24 18:21:09 +020072 t.setWindowCrop(leash, tmp.transformation.getClipRect());
73 }
74
75 @Override
76 public long calculateStatusBarTransitionStartTime() {
77 TranslateAnimation openTranslateAnimation = findTranslateAnimation(mAnimation);
78 if (openTranslateAnimation != null) {
79
80 // Some interpolators are extremely quickly mostly finished, but not completely. For
81 // our purposes, we need to find the fraction for which ther interpolator is mostly
82 // there, and use that value for the calculation.
83 float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
84 return SystemClock.uptimeMillis()
85 + openTranslateAnimation.getStartOffset()
86 + (long)(openTranslateAnimation.getDuration() * t)
87 - STATUS_BAR_TRANSITION_DURATION;
88 } else {
89 return SystemClock.uptimeMillis();
90 }
91 }
92
Jorim Jaggi2e3c31d2017-11-20 19:49:00 +010093 @Override
94 public boolean canSkipFirstFrame() {
95 return mCanSkipFirstFrame;
96 }
97
Jorim Jaggif5f9e122017-10-24 18:21:09 +020098 /**
99 * Tries to find a {@link TranslateAnimation} inside the {@code animation}.
100 *
101 * @return the found animation, {@code null} otherwise
102 */
103 private static TranslateAnimation findTranslateAnimation(Animation animation) {
104 if (animation instanceof TranslateAnimation) {
105 return (TranslateAnimation) animation;
106 } else if (animation instanceof AnimationSet) {
107 AnimationSet set = (AnimationSet) animation;
108 for (int i = 0; i < set.getAnimations().size(); i++) {
109 Animation a = set.getAnimations().get(i);
110 if (a instanceof TranslateAnimation) {
111 return (TranslateAnimation) a;
112 }
113 }
114 }
115 return null;
116 }
117
118 /**
119 * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
120 * {@code interpolator(t + eps) > 0.99}.
121 */
122 private static float findAlmostThereFraction(Interpolator interpolator) {
123 float val = 0.5f;
124 float adj = 0.25f;
125 while (adj >= 0.01f) {
126 if (interpolator.getInterpolation(val) < 0.99f) {
127 val += adj;
128 } else {
129 val -= adj;
130 }
131 adj /= 2;
132 }
133 return val;
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200134 }
135
Jorim Jaggia5e10572017-11-15 14:36:26 +0100136 private static class TmpValues {
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200137 final Transformation transformation = new Transformation();
138 final float[] floats = new float[9];
139 }
140}