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