1 /*
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 
17 package com.android.server.wm;
18 
19 import static android.view.SurfaceControl.METADATA_OWNER_UID;
20 import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
21 
22 import static com.android.server.wm.AppWindowThumbnailProto.HEIGHT;
23 import static com.android.server.wm.AppWindowThumbnailProto.SURFACE_ANIMATOR;
24 import static com.android.server.wm.AppWindowThumbnailProto.WIDTH;
25 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
26 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
27 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
28 import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
29 
30 import android.graphics.GraphicBuffer;
31 import android.graphics.PixelFormat;
32 import android.graphics.Point;
33 import android.os.Binder;
34 import android.util.Slog;
35 import android.util.proto.ProtoOutputStream;
36 import android.view.Surface;
37 import android.view.SurfaceControl;
38 import android.view.SurfaceControl.Builder;
39 import android.view.SurfaceControl.Transaction;
40 import android.view.animation.Animation;
41 
42 import com.android.server.wm.SurfaceAnimator.Animatable;
43 
44 /**
45  * Represents a surface that is displayed over an {@link AppWindowToken}
46  */
47 class AppWindowThumbnail implements Animatable {
48 
49     private static final String TAG = TAG_WITH_CLASS_NAME ? "AppWindowThumbnail" : TAG_WM;
50 
51     private final AppWindowToken mAppToken;
52     private SurfaceControl mSurfaceControl;
53     private final SurfaceAnimator mSurfaceAnimator;
54     private final int mWidth;
55     private final int mHeight;
56     private final boolean mRelative;
57 
AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader)58     AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader) {
59         this(t, appToken, thumbnailHeader, false /* relative */);
60     }
61 
62     /**
63      * @param t Transaction to create the thumbnail in.
64      * @param appToken {@link AppWindowToken} to associate this thumbnail with.
65      * @param thumbnailHeader A thumbnail or placeholder for thumbnail to initialize with.
66      * @param relative Whether this thumbnail will be a child of appToken (and thus positioned
67      *                 relative to it) or not.
68      */
AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader, boolean relative)69     AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader,
70             boolean relative) {
71         this(t, appToken, thumbnailHeader, relative, new Surface(), null);
72     }
73 
AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader, boolean relative, Surface drawSurface, SurfaceAnimator animator)74     AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader,
75             boolean relative, Surface drawSurface, SurfaceAnimator animator) {
76         mAppToken = appToken;
77         mRelative = relative;
78         if (animator != null) {
79             mSurfaceAnimator = animator;
80         } else {
81             // We can't use a delegating constructor since we need to
82             // reference this::onAnimationFinished
83             mSurfaceAnimator =
84                 new SurfaceAnimator(this, this::onAnimationFinished, appToken.mWmService);
85         }
86         mWidth = thumbnailHeader.getWidth();
87         mHeight = thumbnailHeader.getHeight();
88 
89         // Create a new surface for the thumbnail
90         WindowState window = appToken.findMainWindow();
91 
92         // TODO: This should be attached as a child to the app token, once the thumbnail animations
93         // use relative coordinates. Once we start animating task we can also consider attaching
94         // this to the task.
95         mSurfaceControl = appToken.makeSurface()
96                 .setName("thumbnail anim: " + appToken.toString())
97                 .setBufferSize(mWidth, mHeight)
98                 .setFormat(PixelFormat.TRANSLUCENT)
99                 .setMetadata(METADATA_WINDOW_TYPE, appToken.windowType)
100                 .setMetadata(METADATA_OWNER_UID,
101                         window != null ? window.mOwnerUid : Binder.getCallingUid())
102                 .build();
103 
104         if (SHOW_TRANSACTIONS) {
105             Slog.i(TAG, "  THUMBNAIL " + mSurfaceControl + ": CREATE");
106         }
107 
108         // Transfer the thumbnail to the surface
109         drawSurface.copyFrom(mSurfaceControl);
110         drawSurface.attachAndQueueBuffer(thumbnailHeader);
111         drawSurface.release();
112         t.show(mSurfaceControl);
113 
114         // We parent the thumbnail to the task, and just place it on top of anything else in the
115         // task.
116         t.setLayer(mSurfaceControl, Integer.MAX_VALUE);
117         if (relative) {
118             t.reparent(mSurfaceControl, appToken.getSurfaceControl());
119         }
120     }
121 
startAnimation(Transaction t, Animation anim)122     void startAnimation(Transaction t, Animation anim) {
123         startAnimation(t, anim, null /* position */);
124     }
125 
startAnimation(Transaction t, Animation anim, Point position)126     void startAnimation(Transaction t, Animation anim, Point position) {
127         anim.restrictDuration(MAX_ANIMATION_DURATION);
128         anim.scaleCurrentDuration(mAppToken.mWmService.getTransitionAnimationScaleLocked());
129         mSurfaceAnimator.startAnimation(t, new LocalAnimationAdapter(
130                 new WindowAnimationSpec(anim, position,
131                         mAppToken.getDisplayContent().mAppTransition.canSkipFirstFrame(),
132                         mAppToken.getDisplayContent().getWindowCornerRadius()),
133                 mAppToken.mWmService.mSurfaceAnimationRunner), false /* hidden */);
134     }
135 
136     /**
137      * Start animation with existing adapter.
138      */
startAnimation(Transaction t, AnimationAdapter anim, boolean hidden)139     void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
140         mSurfaceAnimator.startAnimation(t, anim, hidden);
141     }
142 
onAnimationFinished()143     private void onAnimationFinished() {
144     }
145 
setShowing(Transaction pendingTransaction, boolean show)146     void setShowing(Transaction pendingTransaction, boolean show) {
147         // TODO: Not needed anymore once thumbnail is attached to the app.
148         if (show) {
149             pendingTransaction.show(mSurfaceControl);
150         } else {
151             pendingTransaction.hide(mSurfaceControl);
152         }
153     }
154 
destroy()155     void destroy() {
156         mSurfaceAnimator.cancelAnimation();
157         getPendingTransaction().remove(mSurfaceControl);
158         mSurfaceControl = null;
159     }
160 
161     /**
162      * Write to a protocol buffer output stream. Protocol buffer message definition is at {@link
163      * com.android.server.wm.AppWindowThumbnailProto}.
164      *
165      * @param proto Stream to write the AppWindowThumbnail object to.
166      * @param fieldId Field Id of the AppWindowThumbnail as defined in the parent message.
167      * @hide
168      */
writeToProto(ProtoOutputStream proto, long fieldId)169     void writeToProto(ProtoOutputStream proto, long fieldId) {
170         final long token = proto.start(fieldId);
171         proto.write(WIDTH, mWidth);
172         proto.write(HEIGHT, mHeight);
173         if (mSurfaceAnimator.isAnimating()) {
174             mSurfaceAnimator.writeToProto(proto, SURFACE_ANIMATOR);
175         }
176         proto.end(token);
177     }
178 
179     @Override
getPendingTransaction()180     public Transaction getPendingTransaction() {
181         return mAppToken.getPendingTransaction();
182     }
183 
184     @Override
commitPendingTransaction()185     public void commitPendingTransaction() {
186         mAppToken.commitPendingTransaction();
187     }
188 
189     @Override
onAnimationLeashCreated(Transaction t, SurfaceControl leash)190     public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
191         t.setLayer(leash, Integer.MAX_VALUE);
192         if (mRelative) {
193             t.reparent(leash, mAppToken.getSurfaceControl());
194         }
195     }
196 
197     @Override
onAnimationLeashLost(Transaction t)198     public void onAnimationLeashLost(Transaction t) {
199 
200         // TODO: Once attached to app token, we don't need to hide it immediately if thumbnail
201         // became visible.
202         t.hide(mSurfaceControl);
203     }
204 
205     @Override
makeAnimationLeash()206     public Builder makeAnimationLeash() {
207         return mAppToken.makeSurface();
208     }
209 
210     @Override
getSurfaceControl()211     public SurfaceControl getSurfaceControl() {
212         return mSurfaceControl;
213     }
214 
215     @Override
getAnimationLeashParent()216     public SurfaceControl getAnimationLeashParent() {
217         return mAppToken.getAppAnimationLayer();
218     }
219 
220     @Override
getParentSurfaceControl()221     public SurfaceControl getParentSurfaceControl() {
222         return mAppToken.getParentSurfaceControl();
223     }
224 
225     @Override
getSurfaceWidth()226     public int getSurfaceWidth() {
227         return mWidth;
228     }
229 
230     @Override
getSurfaceHeight()231     public int getSurfaceHeight() {
232         return mHeight;
233     }
234 }
235