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