1 /* 2 * Copyright (C) 2022 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.wm.shell.transition; 18 19 import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; 20 21 import android.graphics.Rect; 22 import android.util.ArrayMap; 23 import android.util.RotationUtils; 24 import android.view.SurfaceControl; 25 import android.window.TransitionInfo; 26 import android.window.WindowContainerToken; 27 28 import androidx.annotation.NonNull; 29 30 import com.android.wm.shell.shared.CounterRotator; 31 import com.android.wm.shell.shared.TransitionUtil; 32 33 import java.util.List; 34 35 /** 36 * The helper class that performs counter-rotate for all "going-away" window containers if they are 37 * still in the old rotation in a transition. 38 */ 39 public class CounterRotatorHelper { 40 private final ArrayMap<WindowContainerToken, CounterRotator> mRotatorMap = new ArrayMap<>(); 41 private final Rect mLastDisplayBounds = new Rect(); 42 private int mLastRotationDelta; 43 44 /** Puts the surface controls of closing changes to counter-rotated surfaces. */ handleClosingChanges(@onNull TransitionInfo info, @NonNull SurfaceControl.Transaction startTransaction, @NonNull TransitionInfo.Change displayRotationChange)45 public void handleClosingChanges(@NonNull TransitionInfo info, 46 @NonNull SurfaceControl.Transaction startTransaction, 47 @NonNull TransitionInfo.Change displayRotationChange) { 48 final int rotationDelta = RotationUtils.deltaRotation( 49 displayRotationChange.getStartRotation(), displayRotationChange.getEndRotation()); 50 final Rect displayBounds = displayRotationChange.getEndAbsBounds(); 51 final int displayW = displayBounds.width(); 52 final int displayH = displayBounds.height(); 53 mLastRotationDelta = rotationDelta; 54 mLastDisplayBounds.set(displayBounds); 55 56 final List<TransitionInfo.Change> changes = info.getChanges(); 57 final int numChanges = changes.size(); 58 for (int i = numChanges - 1; i >= 0; --i) { 59 final TransitionInfo.Change change = changes.get(i); 60 final WindowContainerToken parent = change.getParent(); 61 if (!TransitionUtil.isClosingType(change.getMode()) 62 || !TransitionInfo.isIndependent(change, info) || parent == null) { 63 continue; 64 } 65 66 CounterRotator crot = mRotatorMap.get(parent); 67 if (crot == null) { 68 crot = new CounterRotator(); 69 crot.setup(startTransaction, info.getChange(parent).getLeash(), rotationDelta, 70 displayW, displayH); 71 final SurfaceControl rotatorSc = crot.getSurface(); 72 if (rotatorSc != null) { 73 // Wallpaper should be placed at the bottom. 74 final int layer = (change.getFlags() & FLAG_IS_WALLPAPER) == 0 75 ? numChanges - i 76 : -1; 77 startTransaction.setLayer(rotatorSc, layer); 78 } 79 mRotatorMap.put(parent, crot); 80 } 81 crot.addChild(startTransaction, change.getLeash()); 82 } 83 } 84 85 /** 86 * Returns the rotated end bounds if the change is put in previous rotation. Otherwise the 87 * original end bounds are returned. 88 */ 89 @NonNull getEndBoundsInStartRotation(@onNull TransitionInfo.Change change)90 public Rect getEndBoundsInStartRotation(@NonNull TransitionInfo.Change change) { 91 if (mLastRotationDelta == 0) return change.getEndAbsBounds(); 92 final Rect rotatedBounds = new Rect(change.getEndAbsBounds()); 93 RotationUtils.rotateBounds(rotatedBounds, mLastDisplayBounds, mLastRotationDelta); 94 return rotatedBounds; 95 } 96 97 /** 98 * Removes the counter rotation surface in the finish transaction. No need to reparent the 99 * children as the finish transaction should have already taken care of that. 100 * 101 * This can only be called after startTransaction for {@link #handleClosingChanges} is applied. 102 */ cleanUp(@onNull SurfaceControl.Transaction finishTransaction)103 public void cleanUp(@NonNull SurfaceControl.Transaction finishTransaction) { 104 for (int i = mRotatorMap.size() - 1; i >= 0; --i) { 105 mRotatorMap.valueAt(i).cleanUp(finishTransaction); 106 } 107 mRotatorMap.clear(); 108 mLastRotationDelta = 0; 109 } 110 } 111