blob: 7aca637748899671e310165a7fff3357c4da6733 [file] [log] [blame]
Vadim Caendca5b932020-04-23 18:26:50 +02001/*
2 * Copyright (C) 2020 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
19import static com.android.server.wm.AnimationSpecProto.WINDOW;
20import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM;
21import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
22
23import android.content.res.Configuration;
24import android.util.proto.ProtoOutputStream;
25import android.view.SurfaceControl;
26import android.view.animation.Animation;
27import android.view.animation.AnimationUtils;
28import android.view.animation.Transformation;
29
30import com.android.internal.R;
31
32import java.io.PrintWriter;
33import java.util.ArrayList;
34
35/**
36 * Controller to fade out and in system ui when applying a fixed rotation transform to a window
37 * token.
38 *
39 * The system bars will be fade out when the fixed rotation transform starts and will be fade in
40 * once all surfaces have been rotated.
41 */
42public class FixedRotationAnimationController {
43
44 private final WindowManagerService mWmService;
45 private boolean mShowRequested = true;
46 private int mTargetRotation = Configuration.ORIENTATION_UNDEFINED;
47 private final ArrayList<WindowState> mAnimatedWindowStates = new ArrayList<>(2);
48 private final Runnable[] mDeferredFinishCallbacks;
49
50 public FixedRotationAnimationController(DisplayContent displayContent) {
51 mWmService = displayContent.mWmService;
52 addAnimatedWindow(displayContent.getDisplayPolicy().getStatusBar());
53 addAnimatedWindow(displayContent.getDisplayPolicy().getNavigationBar());
54 mDeferredFinishCallbacks = new Runnable[mAnimatedWindowStates.size()];
55 }
56
57 private void addAnimatedWindow(WindowState windowState) {
58 if (windowState != null) {
59 mAnimatedWindowStates.add(windowState);
60 }
61 }
62
63 /**
64 * Show the previously hidden {@link WindowToken} if their surfaces have already been rotated.
65 *
66 * @return True if the show animation has been started, in which case the caller no longer needs
67 * this {@link FixedRotationAnimationController}.
68 */
69 boolean show() {
70 if (!mShowRequested && readyToShow()) {
71 mShowRequested = true;
72 for (int i = mAnimatedWindowStates.size() - 1; i >= 0; i--) {
73 WindowState windowState = mAnimatedWindowStates.get(i);
74 fadeWindowToken(true, windowState.getParent(), i);
75 }
76 return true;
77 }
78 return false;
79 }
80
81 void hide(int targetRotation) {
82 mTargetRotation = targetRotation;
83 if (mShowRequested) {
84 mShowRequested = false;
85 for (int i = mAnimatedWindowStates.size() - 1; i >= 0; i--) {
86 WindowState windowState = mAnimatedWindowStates.get(i);
87 fadeWindowToken(false /* show */, windowState.getParent(), i);
88 }
89 }
90 }
91
92 void cancel() {
93 for (int i = mAnimatedWindowStates.size() - 1; i >= 0; i--) {
94 WindowState windowState = mAnimatedWindowStates.get(i);
95 mShowRequested = true;
96 fadeWindowToken(true /* show */, windowState.getParent(), i);
97 }
98 }
99
100 private void fadeWindowToken(boolean show, WindowContainer<WindowToken> windowToken,
101 int index) {
102 Animation animation = AnimationUtils.loadAnimation(mWmService.mContext,
103 show ? R.anim.fade_in : R.anim.fade_out);
104 LocalAnimationAdapter.AnimationSpec windowAnimationSpec = createAnimationSpec(animation);
105
106 FixedRotationAnimationAdapter animationAdapter = new FixedRotationAnimationAdapter(
107 windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, index);
108
109 // We deferred the end of the animation when hiding the token, so we need to end it now that
110 // it's shown again.
111 SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> {
112 if (mDeferredFinishCallbacks[index] != null) {
113 mDeferredFinishCallbacks[index].run();
114 mDeferredFinishCallbacks[index] = null;
115 }
116 } : null;
117 windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter,
118 mShowRequested, ANIMATION_TYPE_FIXED_TRANSFORM, finishedCallback);
119 }
120
121 /**
122 * Check if all the mAnimatedWindowState's surfaces have been rotated to the
123 * mTargetRotation.
124 */
125 private boolean readyToShow() {
126 for (int i = mAnimatedWindowStates.size() - 1; i >= 0; i--) {
127 WindowState windowState = mAnimatedWindowStates.get(i);
128 if (windowState.getConfiguration().windowConfiguration.getRotation()
129 != mTargetRotation || windowState.mPendingSeamlessRotate != null) {
130 return false;
131 }
132 }
133 return true;
134 }
135
136
137 private LocalAnimationAdapter.AnimationSpec createAnimationSpec(Animation animation) {
138 return new LocalAnimationAdapter.AnimationSpec() {
139
140 Transformation mTransformation = new Transformation();
141
142 @Override
143 public boolean getShowWallpaper() {
144 return true;
145 }
146
147 @Override
148 public long getDuration() {
149 return animation.getDuration();
150 }
151
152 @Override
153 public void apply(SurfaceControl.Transaction t, SurfaceControl leash,
154 long currentPlayTime) {
155 mTransformation.clear();
156 animation.getTransformation(currentPlayTime, mTransformation);
157 t.setAlpha(leash, mTransformation.getAlpha());
158 }
159
160 @Override
161 public void dump(PrintWriter pw, String prefix) {
162 pw.print(prefix);
163 pw.println(animation);
164 }
165
166 @Override
167 public void dumpDebugInner(ProtoOutputStream proto) {
168 final long token = proto.start(WINDOW);
169 proto.write(ANIMATION, animation.toString());
170 proto.end(token);
171 }
172 };
173 }
174
175 private class FixedRotationAnimationAdapter extends LocalAnimationAdapter {
176 private final boolean mShow;
177 private final int mIndex;
178
179 FixedRotationAnimationAdapter(AnimationSpec windowAnimationSpec,
180 SurfaceAnimationRunner surfaceAnimationRunner, boolean show, int index) {
181 super(windowAnimationSpec, surfaceAnimationRunner);
182 mShow = show;
183 mIndex = index;
184 }
185
186 @Override
187 public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
188 // We defer the end of the hide animation to ensure the tokens stay hidden until
189 // we show them again.
190 if (!mShow) {
191 mDeferredFinishCallbacks[mIndex] = endDeferFinishCallback;
192 return true;
193 }
194 return false;
195 }
196 }
197}