blob: 98c77ac719f9d43292da724c4383c6ecf19232ae [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;
chaviw23012112017-12-20 15:29:04 -080020import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;
21import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070022import static com.android.server.wm.AnimationSpecProto.WINDOW;
23import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
Jorim Jaggif5f9e122017-10-24 18:21:09 +020024
Jorim Jaggi21c39a72017-10-20 15:47:51 +020025import android.graphics.Point;
chaviw23012112017-12-20 15:29:04 -080026import android.graphics.Rect;
Jorim Jaggif5f9e122017-10-24 18:21:09 +020027import android.os.SystemClock;
Jorim Jaggif75d1612018-02-27 15:05:21 +010028import android.util.proto.ProtoOutputStream;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020029import android.view.SurfaceControl;
30import android.view.SurfaceControl.Transaction;
31import android.view.animation.Animation;
Jorim Jaggif5f9e122017-10-24 18:21:09 +020032import android.view.animation.AnimationSet;
33import android.view.animation.Interpolator;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020034import android.view.animation.Transformation;
Jorim Jaggif5f9e122017-10-24 18:21:09 +020035import android.view.animation.TranslateAnimation;
Jorim Jaggi21c39a72017-10-20 15:47:51 +020036
37import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
38
Jorim Jaggif75d1612018-02-27 15:05:21 +010039import java.io.PrintWriter;
40
Jorim Jaggi21c39a72017-10-20 15:47:51 +020041/**
42 * Animation spec for regular window animations.
43 */
44public class WindowAnimationSpec implements AnimationSpec {
45
46 private Animation mAnimation;
47 private final Point mPosition = new Point();
Jorim Jaggia5e10572017-11-15 14:36:26 +010048 private final ThreadLocal<TmpValues> mThreadLocalTmps = ThreadLocal.withInitial(TmpValues::new);
Jorim Jaggi2e3c31d2017-11-20 19:49:00 +010049 private final boolean mCanSkipFirstFrame;
Jorim Jaggiaa763cd2018-03-22 23:20:36 +010050 private final boolean mIsAppAnimation;
chaviw23012112017-12-20 15:29:04 -080051 private final Rect mStackBounds = new Rect();
52 private int mStackClipMode;
53 private final Rect mTmpRect = new Rect();
Jorim Jaggi21c39a72017-10-20 15:47:51 +020054
Jorim Jaggi2e3c31d2017-11-20 19:49:00 +010055 public WindowAnimationSpec(Animation animation, Point position, boolean canSkipFirstFrame) {
Jorim Jaggiaa763cd2018-03-22 23:20:36 +010056 this(animation, position, null /* stackBounds */, canSkipFirstFrame, STACK_CLIP_NONE,
57 false /* isAppAnimation */);
chaviw23012112017-12-20 15:29:04 -080058 }
59
60 public WindowAnimationSpec(Animation animation, Point position, Rect stackBounds,
Jorim Jaggiaa763cd2018-03-22 23:20:36 +010061 boolean canSkipFirstFrame, int stackClipMode, boolean isAppAnimation) {
Jorim Jaggi21c39a72017-10-20 15:47:51 +020062 mAnimation = animation;
chaviw23012112017-12-20 15:29:04 -080063 if (position != null) {
64 mPosition.set(position.x, position.y);
65 }
Jorim Jaggi2e3c31d2017-11-20 19:49:00 +010066 mCanSkipFirstFrame = canSkipFirstFrame;
Jorim Jaggiaa763cd2018-03-22 23:20:36 +010067 mIsAppAnimation = isAppAnimation;
chaviw23012112017-12-20 15:29:04 -080068 mStackClipMode = stackClipMode;
69 if (stackBounds != null) {
70 mStackBounds.set(stackBounds);
71 }
Jorim Jaggi21c39a72017-10-20 15:47:51 +020072 }
73
74 @Override
Jorim Jaggi82c17862018-02-21 17:50:18 +010075 public boolean getShowWallpaper() {
76 return mAnimation.getShowWallpaper();
77 }
78
79 @Override
Jorim Jaggi21c39a72017-10-20 15:47:51 +020080 public int getBackgroundColor() {
81 return mAnimation.getBackgroundColor();
82 }
83
84 @Override
85 public long getDuration() {
86 return mAnimation.computeDurationHint();
87 }
88
89 @Override
90 public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
Jorim Jaggia5e10572017-11-15 14:36:26 +010091 final TmpValues tmp = mThreadLocalTmps.get();
Jorim Jaggi21c39a72017-10-20 15:47:51 +020092 tmp.transformation.clear();
93 mAnimation.getTransformation(currentPlayTime, tmp.transformation);
94 tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
95 t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
96 t.setAlpha(leash, tmp.transformation.getAlpha());
Vishnu Naira2977262018-07-26 13:31:26 -070097 if (mStackClipMode == STACK_CLIP_NONE || mStackClipMode == STACK_CLIP_AFTER_ANIM) {
chaviw23012112017-12-20 15:29:04 -080098 t.setWindowCrop(leash, tmp.transformation.getClipRect());
99 } else {
chaviw977482a2017-12-28 11:35:53 -0800100 mTmpRect.set(mStackBounds);
101 mTmpRect.intersect(tmp.transformation.getClipRect());
chaviw23012112017-12-20 15:29:04 -0800102 t.setWindowCrop(leash, mTmpRect);
103 }
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200104 }
105
106 @Override
107 public long calculateStatusBarTransitionStartTime() {
108 TranslateAnimation openTranslateAnimation = findTranslateAnimation(mAnimation);
109 if (openTranslateAnimation != null) {
110
111 // Some interpolators are extremely quickly mostly finished, but not completely. For
112 // our purposes, we need to find the fraction for which ther interpolator is mostly
113 // there, and use that value for the calculation.
114 float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
115 return SystemClock.uptimeMillis()
116 + openTranslateAnimation.getStartOffset()
117 + (long)(openTranslateAnimation.getDuration() * t)
118 - STATUS_BAR_TRANSITION_DURATION;
119 } else {
120 return SystemClock.uptimeMillis();
121 }
122 }
123
Jorim Jaggi2e3c31d2017-11-20 19:49:00 +0100124 @Override
125 public boolean canSkipFirstFrame() {
126 return mCanSkipFirstFrame;
127 }
128
Jorim Jaggif75d1612018-02-27 15:05:21 +0100129 @Override
Jorim Jaggiaa763cd2018-03-22 23:20:36 +0100130 public boolean needsEarlyWakeup() {
131 return mIsAppAnimation;
132 }
133
134 @Override
Jorim Jaggif75d1612018-02-27 15:05:21 +0100135 public void dump(PrintWriter pw, String prefix) {
136 pw.print(prefix); pw.println(mAnimation);
137 }
138
139 @Override
140 public void writeToProtoInner(ProtoOutputStream proto) {
141 final long token = proto.start(WINDOW);
142 proto.write(ANIMATION, mAnimation.toString());
143 proto.end(token);
144 }
145
Jorim Jaggif5f9e122017-10-24 18:21:09 +0200146 /**
147 * Tries to find a {@link TranslateAnimation} inside the {@code animation}.
148 *
149 * @return the found animation, {@code null} otherwise
150 */
151 private static TranslateAnimation findTranslateAnimation(Animation animation) {
152 if (animation instanceof TranslateAnimation) {
153 return (TranslateAnimation) animation;
154 } else if (animation instanceof AnimationSet) {
155 AnimationSet set = (AnimationSet) animation;
156 for (int i = 0; i < set.getAnimations().size(); i++) {
157 Animation a = set.getAnimations().get(i);
158 if (a instanceof TranslateAnimation) {
159 return (TranslateAnimation) a;
160 }
161 }
162 }
163 return null;
164 }
165
166 /**
167 * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
168 * {@code interpolator(t + eps) > 0.99}.
169 */
170 private static float findAlmostThereFraction(Interpolator interpolator) {
171 float val = 0.5f;
172 float adj = 0.25f;
173 while (adj >= 0.01f) {
174 if (interpolator.getInterpolation(val) < 0.99f) {
175 val += adj;
176 } else {
177 val -= adj;
178 }
179 adj /= 2;
180 }
181 return val;
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200182 }
183
Jorim Jaggia5e10572017-11-15 14:36:26 +0100184 private static class TmpValues {
Jorim Jaggi21c39a72017-10-20 15:47:51 +0200185 final Transformation transformation = new Transformation();
186 final float[] floats = new float[9];
187 }
188}