| /* |
| * Copyright (C) 2022 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.wm.shell.transition; |
| |
| import static android.window.TransitionInfo.FLAG_IS_WALLPAPER; |
| |
| import android.graphics.Rect; |
| import android.util.ArrayMap; |
| import android.util.RotationUtils; |
| import android.view.SurfaceControl; |
| import android.window.TransitionInfo; |
| import android.window.WindowContainerToken; |
| |
| import androidx.annotation.NonNull; |
| |
| import com.android.wm.shell.util.CounterRotator; |
| import com.android.wm.shell.util.TransitionUtil; |
| |
| import java.util.List; |
| |
| /** |
| * The helper class that performs counter-rotate for all "going-away" window containers if they are |
| * still in the old rotation in a transition. |
| */ |
| public class CounterRotatorHelper { |
| private final ArrayMap<WindowContainerToken, CounterRotator> mRotatorMap = new ArrayMap<>(); |
| private final Rect mLastDisplayBounds = new Rect(); |
| private int mLastRotationDelta; |
| |
| /** Puts the surface controls of closing changes to counter-rotated surfaces. */ |
| public void handleClosingChanges(@NonNull TransitionInfo info, |
| @NonNull SurfaceControl.Transaction startTransaction, |
| @NonNull TransitionInfo.Change displayRotationChange) { |
| final int rotationDelta = RotationUtils.deltaRotation( |
| displayRotationChange.getStartRotation(), displayRotationChange.getEndRotation()); |
| final Rect displayBounds = displayRotationChange.getEndAbsBounds(); |
| final int displayW = displayBounds.width(); |
| final int displayH = displayBounds.height(); |
| mLastRotationDelta = rotationDelta; |
| mLastDisplayBounds.set(displayBounds); |
| |
| final List<TransitionInfo.Change> changes = info.getChanges(); |
| final int numChanges = changes.size(); |
| for (int i = numChanges - 1; i >= 0; --i) { |
| final TransitionInfo.Change change = changes.get(i); |
| final WindowContainerToken parent = change.getParent(); |
| if (!TransitionUtil.isClosingType(change.getMode()) |
| || !TransitionInfo.isIndependent(change, info) || parent == null) { |
| continue; |
| } |
| |
| CounterRotator crot = mRotatorMap.get(parent); |
| if (crot == null) { |
| crot = new CounterRotator(); |
| crot.setup(startTransaction, info.getChange(parent).getLeash(), rotationDelta, |
| displayW, displayH); |
| final SurfaceControl rotatorSc = crot.getSurface(); |
| if (rotatorSc != null) { |
| // Wallpaper should be placed at the bottom. |
| final int layer = (change.getFlags() & FLAG_IS_WALLPAPER) == 0 |
| ? numChanges - i |
| : -1; |
| startTransaction.setLayer(rotatorSc, layer); |
| } |
| mRotatorMap.put(parent, crot); |
| } |
| crot.addChild(startTransaction, change.getLeash()); |
| } |
| } |
| |
| /** |
| * Returns the rotated end bounds if the change is put in previous rotation. Otherwise the |
| * original end bounds are returned. |
| */ |
| @NonNull |
| public Rect getEndBoundsInStartRotation(@NonNull TransitionInfo.Change change) { |
| if (mLastRotationDelta == 0) return change.getEndAbsBounds(); |
| final Rect rotatedBounds = new Rect(change.getEndAbsBounds()); |
| RotationUtils.rotateBounds(rotatedBounds, mLastDisplayBounds, mLastRotationDelta); |
| return rotatedBounds; |
| } |
| |
| /** |
| * Removes the counter rotation surface in the finish transaction. No need to reparent the |
| * children as the finish transaction should have already taken care of that. |
| * |
| * This can only be called after startTransaction for {@link #handleClosingChanges} is applied. |
| */ |
| public void cleanUp(@NonNull SurfaceControl.Transaction finishTransaction) { |
| for (int i = mRotatorMap.size() - 1; i >= 0; --i) { |
| mRotatorMap.valueAt(i).cleanUp(finishTransaction); |
| } |
| mRotatorMap.clear(); |
| mLastRotationDelta = 0; |
| } |
| } |