1 /*
2  * Copyright (C) 2021 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.util;
18 
19 import android.graphics.Point;
20 import android.util.RotationUtils;
21 import android.view.SurfaceControl;
22 
23 /**
24  * Utility class that takes care of rotating unchanging child-surfaces to match the parent rotation
25  * during a transition animation. This gives the illusion that the child surfaces haven't rotated
26  * relative to the screen.
27  */
28 public class CounterRotator {
29     private SurfaceControl mSurface = null;
30 
31     /** Gets the surface with the counter-rotation. */
getSurface()32     public SurfaceControl getSurface() {
33         return mSurface;
34     }
35 
36     /**
37      * Sets up this rotator.
38      *
39      * @param rotateDelta is the forward rotation change (the rotation the display is making).
40      * @param parentW (and H) Is the size of the rotating parent after the rotation.
41      */
setup(SurfaceControl.Transaction t, SurfaceControl parent, int rotateDelta, float parentW, float parentH)42     public void setup(SurfaceControl.Transaction t, SurfaceControl parent, int rotateDelta,
43             float parentW, float parentH) {
44         if (rotateDelta == 0) return;
45         mSurface = new SurfaceControl.Builder()
46                 .setName("Transition Unrotate")
47                 .setContainerLayer()
48                 .setParent(parent)
49                 .build();
50         // Rotate forward to match the new rotation (rotateDelta is the forward rotation the parent
51         // already took). Child surfaces will be in the old rotation relative to the new parent
52         // rotation, so we need to forward-rotate the child surfaces to match.
53         RotationUtils.rotateSurface(t, mSurface, rotateDelta);
54         final Point tmpPt = new Point(0, 0);
55         // parentW/H are the size in the END rotation, the rotation utilities expect the starting
56         // size. So swap them if necessary
57         if ((rotateDelta % 2) != 0) {
58             final float w = parentW;
59             parentW = parentH;
60             parentH = w;
61         }
62         RotationUtils.rotatePoint(tmpPt, rotateDelta, (int) parentW, (int) parentH);
63         t.setPosition(mSurface, tmpPt.x, tmpPt.y);
64         t.show(mSurface);
65     }
66 
67     /**
68      * Adds a surface that needs to be counter-rotate.
69      */
addChild(SurfaceControl.Transaction t, SurfaceControl child)70     public void addChild(SurfaceControl.Transaction t, SurfaceControl child) {
71         if (mSurface == null) return;
72         t.reparent(child, mSurface);
73     }
74 
75     /**
76      * Clean-up. Since finishTransaction should reset all change leashes, we only need to remove the
77      * counter rotation surface.
78      */
cleanUp(SurfaceControl.Transaction finishTransaction)79     public void cleanUp(SurfaceControl.Transaction finishTransaction) {
80         if (mSurface == null) return;
81         finishTransaction.remove(mSurface);
82     }
83 }
84