1 /* 2 * Copyright (C) 2016 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.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 20 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 21 22 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; 23 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WALLPAPER; 24 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 25 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 26 27 import android.annotation.Nullable; 28 import android.os.Bundle; 29 import android.os.IBinder; 30 import android.os.RemoteException; 31 import android.view.animation.Animation; 32 33 import com.android.internal.protolog.common.ProtoLog; 34 35 import java.util.function.Consumer; 36 37 /** 38 * A token that represents a set of wallpaper windows. 39 */ 40 class WallpaperWindowToken extends WindowToken { 41 42 private static final String TAG = TAG_WITH_CLASS_NAME ? "WallpaperWindowToken" : TAG_WM; 43 44 private boolean mVisibleRequested = false; 45 WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit, DisplayContent dc, boolean ownerCanManageAppTokens)46 WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit, 47 DisplayContent dc, boolean ownerCanManageAppTokens) { 48 this(service, token, explicit, dc, ownerCanManageAppTokens, null /* options */); 49 } 50 WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit, DisplayContent dc, boolean ownerCanManageAppTokens, @Nullable Bundle options)51 WallpaperWindowToken(WindowManagerService service, IBinder token, boolean explicit, 52 DisplayContent dc, boolean ownerCanManageAppTokens, @Nullable Bundle options) { 53 super(service, token, TYPE_WALLPAPER, explicit, dc, ownerCanManageAppTokens, 54 false /* roundedCornerOverlay */, false /* fromClientToken */, options); 55 dc.mWallpaperController.addWallpaperToken(this); 56 setWindowingMode(WINDOWING_MODE_FULLSCREEN); 57 } 58 59 @Override asWallpaperToken()60 WallpaperWindowToken asWallpaperToken() { 61 return this; 62 } 63 64 @Override setExiting(boolean animateExit)65 void setExiting(boolean animateExit) { 66 super.setExiting(animateExit); 67 mDisplayContent.mWallpaperController.removeWallpaperToken(this); 68 } 69 sendWindowWallpaperCommand( String action, int x, int y, int z, Bundle extras, boolean sync)70 void sendWindowWallpaperCommand( 71 String action, int x, int y, int z, Bundle extras, boolean sync) { 72 for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { 73 final WindowState wallpaper = mChildren.get(wallpaperNdx); 74 try { 75 wallpaper.mClient.dispatchWallpaperCommand(action, x, y, z, extras, sync); 76 // We only want to be synchronous with one wallpaper. 77 sync = false; 78 } catch (RemoteException e) { 79 } 80 } 81 } 82 updateWallpaperOffset(boolean sync)83 void updateWallpaperOffset(boolean sync) { 84 final WallpaperController wallpaperController = mDisplayContent.mWallpaperController; 85 for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { 86 final WindowState wallpaper = mChildren.get(wallpaperNdx); 87 if (wallpaperController.updateWallpaperOffset(wallpaper, sync)) { 88 // We only want to be synchronous with one wallpaper. 89 sync = false; 90 } 91 } 92 } 93 94 /** 95 * Starts {@param anim} on all children. 96 */ startAnimation(Animation anim)97 void startAnimation(Animation anim) { 98 for (int ndx = mChildren.size() - 1; ndx >= 0; ndx--) { 99 final WindowState windowState = mChildren.get(ndx); 100 windowState.startAnimation(anim); 101 } 102 } 103 104 /** Returns {@code true} if visibility is changed. */ updateWallpaperWindows(boolean visible)105 boolean updateWallpaperWindows(boolean visible) { 106 boolean changed = false; 107 if (mVisibleRequested != visible) { 108 ProtoLog.d(WM_DEBUG_WALLPAPER, "Wallpaper token %s visible=%b", 109 token, visible); 110 setVisibility(visible); 111 changed = true; 112 } 113 if (mTransitionController.isShellTransitionsEnabled()) { 114 // Apply legacy fixed rotation to wallpaper if it is becoming visible 115 if (!mTransitionController.useShellTransitionsRotation() && changed && visible) { 116 final WindowState wallpaperTarget = 117 mDisplayContent.mWallpaperController.getWallpaperTarget(); 118 if (wallpaperTarget != null && wallpaperTarget.mToken.hasFixedRotationTransform()) { 119 linkFixedRotationTransform(wallpaperTarget.mToken); 120 } 121 } 122 return changed; 123 } 124 125 final WindowState wallpaperTarget = 126 mDisplayContent.mWallpaperController.getWallpaperTarget(); 127 128 if (visible && wallpaperTarget != null) { 129 final RecentsAnimationController recentsAnimationController = 130 mWmService.getRecentsAnimationController(); 131 final BackNaviAnimationController bac = mWmService.getBackNaviAnimationController(); 132 if (recentsAnimationController != null 133 && recentsAnimationController.isAnimatingTask(wallpaperTarget.getTask())) { 134 // If the Recents animation is running, and the wallpaper target is the animating 135 // task we want the wallpaper to be rotated in the same orientation as the 136 // RecentsAnimation's target (e.g the launcher) 137 recentsAnimationController.linkFixedRotationTransformIfNeeded(this); 138 } else if (bac != null && bac.isAnimatingTask(wallpaperTarget.getTask())) { 139 bac.linkFixedRotationTransformIfNeeded(this); 140 } else if ((wallpaperTarget.mActivityRecord == null 141 // Ignore invisible activity because it may be moving to background. 142 || wallpaperTarget.mActivityRecord.isVisibleRequested()) 143 && wallpaperTarget.mToken.hasFixedRotationTransform()) { 144 // If the wallpaper target has a fixed rotation, we want the wallpaper to follow its 145 // rotation 146 linkFixedRotationTransform(wallpaperTarget.mToken); 147 } 148 } 149 150 setVisible(visible); 151 return changed; 152 } 153 setVisible(boolean visible)154 private void setVisible(boolean visible) { 155 final boolean wasClientVisible = isClientVisible(); 156 setClientVisible(visible); 157 if (visible && !wasClientVisible) { 158 for (int i = mChildren.size() - 1; i >= 0; i--) { 159 final WindowState wallpaper = mChildren.get(i); 160 wallpaper.requestUpdateWallpaperIfNeeded(); 161 } 162 } 163 } 164 165 /** 166 * Sets the requested visibility of this token. The visibility may not be if this is part of a 167 * transition. In that situation, make sure to call {@link #commitVisibility} when done. 168 */ setVisibility(boolean visible)169 void setVisibility(boolean visible) { 170 if (mVisibleRequested != visible) { 171 // Before setting mVisibleRequested so we can track changes. 172 mTransitionController.collect(this); 173 174 setVisibleRequested(visible); 175 } 176 177 // If in a transition, defer commits for activities that are going invisible 178 if (!visible && (mTransitionController.inTransition() 179 || getDisplayContent().mAppTransition.isRunning())) { 180 return; 181 } 182 183 commitVisibility(visible); 184 } 185 186 /** 187 * Commits the visibility of this token. This will directly update the visibility without 188 * regard for other state (like being in a transition). 189 */ commitVisibility(boolean visible)190 void commitVisibility(boolean visible) { 191 if (visible == isVisible()) return; 192 193 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, 194 "commitVisibility: %s: visible=%b mVisibleRequested=%b", this, 195 isVisible(), mVisibleRequested); 196 197 setVisibleRequested(visible); 198 setVisible(visible); 199 } 200 hasVisibleNotDrawnWallpaper()201 boolean hasVisibleNotDrawnWallpaper() { 202 if (!isVisible()) return false; 203 for (int j = mChildren.size() - 1; j >= 0; --j) { 204 final WindowState wallpaper = mChildren.get(j); 205 if (!wallpaper.isDrawn() && wallpaper.isVisible()) { 206 return true; 207 } 208 } 209 return false; 210 } 211 212 @Override forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback)213 void forAllWallpaperWindows(Consumer<WallpaperWindowToken> callback) { 214 callback.accept(this); 215 } 216 217 @Override fillsParent()218 boolean fillsParent() { 219 return true; 220 } 221 222 @Override showWallpaper()223 boolean showWallpaper() { 224 return false; 225 } 226 setVisibleRequested(boolean visible)227 void setVisibleRequested(boolean visible) { 228 if (mVisibleRequested == visible) return; 229 mVisibleRequested = visible; 230 setInsetsFrozen(!visible); 231 } 232 233 @Override isVisibleRequested()234 boolean isVisibleRequested() { 235 return mVisibleRequested; 236 } 237 238 @Override isVisible()239 boolean isVisible() { 240 return isClientVisible(); 241 } 242 243 @Override toString()244 public String toString() { 245 if (stringName == null) { 246 StringBuilder sb = new StringBuilder(); 247 sb.append("WallpaperWindowToken{"); 248 sb.append(Integer.toHexString(System.identityHashCode(this))); 249 sb.append(" token="); sb.append(token); sb.append('}'); 250 stringName = sb.toString(); 251 } 252 return stringName; 253 } 254 } 255