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.view.SurfaceControl;
20 
21 import java.util.ArrayList;
22 
23 /**
24  * Utility class that takes care of counter-rotating surfaces during a transition animation.
25  */
26 public class CounterRotator {
27     SurfaceControl mSurface = null;
28     ArrayList<SurfaceControl> mRotateChildren = null;
29 
30     /** Gets the surface with the counter-rotation. */
getSurface()31     public SurfaceControl getSurface() {
32         return mSurface;
33     }
34 
35     /**
36      * Sets up this rotator.
37      *
38      * @param rotateDelta is the forward rotation change (the rotation the display is making).
39      * @param displayW (and H) Is the size of the rotating display.
40      */
setup(SurfaceControl.Transaction t, SurfaceControl parent, int rotateDelta, float displayW, float displayH)41     public void setup(SurfaceControl.Transaction t, SurfaceControl parent, int rotateDelta,
42             float displayW, float displayH) {
43         if (rotateDelta == 0) return;
44         mRotateChildren = new ArrayList<>();
45         // We want to counter-rotate, so subtract from 4
46         rotateDelta = 4 - (rotateDelta + 4) % 4;
47         mSurface = new SurfaceControl.Builder()
48                 .setName("Transition Unrotate")
49                 .setContainerLayer()
50                 .setParent(parent)
51                 .build();
52         // column-major
53         if (rotateDelta == 1) {
54             t.setMatrix(mSurface, 0, 1, -1, 0);
55             t.setPosition(mSurface, displayW, 0);
56         } else if (rotateDelta == 2) {
57             t.setMatrix(mSurface, -1, 0, 0, -1);
58             t.setPosition(mSurface, displayW, displayH);
59         } else if (rotateDelta == 3) {
60             t.setMatrix(mSurface, 0, -1, 1, 0);
61             t.setPosition(mSurface, 0, displayH);
62         }
63         t.show(mSurface);
64     }
65 
66     /**
67      * Add a surface that needs to be counter-rotate.
68      */
addChild(SurfaceControl.Transaction t, SurfaceControl child)69     public void addChild(SurfaceControl.Transaction t, SurfaceControl child) {
70         if (mSurface == null) return;
71         t.reparent(child, mSurface);
72         mRotateChildren.add(child);
73     }
74 
75     /**
76      * Clean-up. This undoes any reparenting and effectively stops the counter-rotation.
77      */
cleanUp(SurfaceControl rootLeash)78     public void cleanUp(SurfaceControl rootLeash) {
79         if (mSurface == null) return;
80         SurfaceControl.Transaction t = new SurfaceControl.Transaction();
81         for (int i = mRotateChildren.size() - 1; i >= 0; --i) {
82             t.reparent(mRotateChildren.get(i), rootLeash);
83         }
84         t.remove(mSurface);
85         t.apply();
86     }
87 }
88