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