1 /*
2  * Copyright (C) 2018 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.view.Surface.ROTATION_270;
20 import static android.view.Surface.ROTATION_90;
21 
22 import android.graphics.Matrix;
23 import android.os.IBinder;
24 import android.view.DisplayInfo;
25 import android.view.Surface.Rotation;
26 import android.view.SurfaceControl;
27 import android.view.SurfaceControl.Transaction;
28 
29 import com.android.server.wm.utils.CoordinateTransforms;
30 
31 import java.io.PrintWriter;
32 import java.io.StringWriter;
33 
34 /**
35  * Helper class for seamless rotation.
36  *
37  * Works by transforming the {@link WindowState} back into the old display rotation.
38  */
39 public class SeamlessRotator {
40 
41     private final Matrix mTransform = new Matrix();
42     private final float[] mFloat9 = new float[9];
43     private final int mOldRotation;
44     private final int mNewRotation;
45     /* If the seamless rotator is used to rotate part of the hierarchy, then provide a transform
46      * hint based on the display orientation if the entire display was rotated. When the display
47      * orientation matches the hierarchy orientation, the fixed transform hint will be removed.
48      * This will prevent allocating different buffer sizes by the graphic producers when the
49      * orientation of a layer changes.
50      */
51     private final boolean mApplyFixedTransformHint;
52     private final int mFixedTransformHint;
53 
54 
SeamlessRotator(@otation int oldRotation, @Rotation int newRotation, DisplayInfo info, boolean applyFixedTransformationHint)55     public SeamlessRotator(@Rotation int oldRotation, @Rotation int newRotation, DisplayInfo info,
56             boolean applyFixedTransformationHint) {
57         mOldRotation = oldRotation;
58         mNewRotation = newRotation;
59         mApplyFixedTransformHint = applyFixedTransformationHint;
60         mFixedTransformHint = oldRotation;
61         final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270;
62         final int pH = flipped ? info.logicalWidth : info.logicalHeight;
63         final int pW = flipped ? info.logicalHeight : info.logicalWidth;
64         // Initialize transform matrix by physical size.
65         final Matrix tmp = new Matrix();
66         CoordinateTransforms.transformLogicalToPhysicalCoordinates(oldRotation, pW, pH, mTransform);
67         CoordinateTransforms.transformPhysicalToLogicalCoordinates(newRotation, pW, pH, tmp);
68         mTransform.postConcat(tmp);
69     }
70 
71     /**
72      * Applies a transform to the {@link WindowContainer} surface that undoes the effect of the
73      * global display rotation.
74      */
unrotate(Transaction transaction, WindowContainer win)75     public void unrotate(Transaction transaction, WindowContainer win) {
76         transaction.setMatrix(win.getSurfaceControl(), mTransform, mFloat9);
77         // WindowState sets the position of the window so transform the position and update it.
78         final float[] winSurfacePos = {win.mLastSurfacePosition.x, win.mLastSurfacePosition.y};
79         mTransform.mapPoints(winSurfacePos);
80         transaction.setPosition(win.getSurfaceControl(), winSurfacePos[0], winSurfacePos[1]);
81         if (mApplyFixedTransformHint) {
82             transaction.setFixedTransformHint(win.mSurfaceControl, mFixedTransformHint);
83         }
84     }
85 
86     /**
87      * Returns the rotation of the display before it started rotating.
88      *
89      * @return the old rotation of the display
90      */
91     @Rotation
getOldRotation()92     public int getOldRotation() {
93         return mOldRotation;
94     }
95 
96     /**
97      * Removes the transform and sets the previously known surface position for {@link WindowState}
98      * surface that undoes the effect of the global display rotation.
99      *
100      * Removing the transform and the result of the {@link WindowState} layout are both tied to the
101      * {@link WindowState} next frame, such that they apply at the same time the client draws the
102      * window in the new orientation.
103      */
finish(Transaction t, WindowContainer win)104     void finish(Transaction t, WindowContainer win) {
105         if (win.mSurfaceControl == null || !win.mSurfaceControl.isValid()) {
106             return;
107         }
108 
109         mTransform.reset();
110         t.setMatrix(win.mSurfaceControl, mTransform, mFloat9);
111         t.setPosition(win.mSurfaceControl, win.mLastSurfacePosition.x, win.mLastSurfacePosition.y);
112         if (mApplyFixedTransformHint) {
113             t.unsetFixedTransformHint(win.mSurfaceControl);
114         }
115     }
116 
dump(PrintWriter pw)117     public void dump(PrintWriter pw) {
118         pw.print("{old="); pw.print(mOldRotation); pw.print(", new="); pw.print(mNewRotation);
119         pw.print("}");
120     }
121 
122     @Override
toString()123     public String toString() {
124         StringWriter sw = new StringWriter();
125         dump(new PrintWriter(sw));
126         return "ForcedSeamlessRotator" + sw.toString();
127     }
128 }
129