• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  * Uses {@link Transaction#deferTransactionUntil(SurfaceControl, IBinder, long)} instead of
40  * latching on the buffer size to allow for seamless 180 degree rotations.
41  */
42 public class SeamlessRotator {
43 
44     private final Matrix mTransform = new Matrix();
45     private final float[] mFloat9 = new float[9];
46     private final int mOldRotation;
47     private final int mNewRotation;
48     /* If the seamless rotator is used to rotate part of the hierarchy, then provide a transform
49      * hint based on the display orientation if the entire display was rotated. When the display
50      * orientation matches the hierarchy orientation, the fixed transform hint will be removed.
51      * This will prevent allocating different buffer sizes by the graphic producers when the
52      * orientation of a layer changes.
53      */
54     private final boolean mApplyFixedTransformHint;
55     private final int mFixedTransformHint;
56 
57 
SeamlessRotator(@otation int oldRotation, @Rotation int newRotation, DisplayInfo info, boolean applyFixedTransformationHint)58     public SeamlessRotator(@Rotation int oldRotation, @Rotation int newRotation, DisplayInfo info,
59             boolean applyFixedTransformationHint) {
60         mOldRotation = oldRotation;
61         mNewRotation = newRotation;
62         mApplyFixedTransformHint = applyFixedTransformationHint;
63         mFixedTransformHint = oldRotation;
64         final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270;
65         final int pH = flipped ? info.logicalWidth : info.logicalHeight;
66         final int pW = flipped ? info.logicalHeight : info.logicalWidth;
67         // Initialize transform matrix by physical size.
68         final Matrix tmp = new Matrix();
69         CoordinateTransforms.transformLogicalToPhysicalCoordinates(oldRotation, pW, pH, mTransform);
70         CoordinateTransforms.transformPhysicalToLogicalCoordinates(newRotation, pW, pH, tmp);
71         mTransform.postConcat(tmp);
72     }
73 
74     /**
75      * Applies a transform to the {@link WindowContainer} surface that undoes the effect of the
76      * global display rotation.
77      */
unrotate(Transaction transaction, WindowContainer win)78     public void unrotate(Transaction transaction, WindowContainer win) {
79         transaction.setMatrix(win.getSurfaceControl(), mTransform, mFloat9);
80         // WindowState sets the position of the window so transform the position and update it.
81         final float[] winSurfacePos = {win.mLastSurfacePosition.x, win.mLastSurfacePosition.y};
82         mTransform.mapPoints(winSurfacePos);
83         transaction.setPosition(win.getSurfaceControl(), winSurfacePos[0], winSurfacePos[1]);
84         if (mApplyFixedTransformHint) {
85             transaction.setFixedTransformHint(win.mSurfaceControl, mFixedTransformHint);
86         }
87     }
88 
89     /**
90      * Returns the rotation of the display before it started rotating.
91      *
92      * @return the old rotation of the display
93      */
94     @Rotation
getOldRotation()95     public int getOldRotation() {
96         return mOldRotation;
97     }
98 
99     /**
100      * Removes the transform and sets the previously known surface position for {@link WindowState}
101      * surface that undoes the effect of the global display rotation.
102      *
103      * Removing the transform and the result of the {@link WindowState} layout are both tied to the
104      * {@link WindowState} next frame, such that they apply at the same time the client draws the
105      * window in the new orientation.
106      *
107      * In the case of a rotation timeout, we want to remove the transform immediately and not defer
108      * it.
109      */
finish(WindowState win, boolean timeout)110     public void finish(WindowState win, boolean timeout) {
111         final Transaction t = win.getPendingTransaction();
112         finish(t, win);
113         if (win.mWinAnimator.mSurfaceController != null && !timeout) {
114             t.deferTransactionUntil(win.mSurfaceControl,
115                     win.getClientViewRootSurface(), win.getFrameNumber());
116             t.deferTransactionUntil(win.mWinAnimator.mSurfaceController.mSurfaceControl,
117                     win.getClientViewRootSurface(), win.getFrameNumber());
118         }
119     }
120 
121     /** Removes the transform and restore to the original last position. */
finish(Transaction t, WindowContainer win)122     void finish(Transaction t, WindowContainer win) {
123         mTransform.reset();
124         t.setMatrix(win.mSurfaceControl, mTransform, mFloat9);
125         t.setPosition(win.mSurfaceControl, win.mLastSurfacePosition.x, win.mLastSurfacePosition.y);
126         if (mApplyFixedTransformHint) {
127             t.unsetFixedTransformHint(win.mSurfaceControl);
128         }
129     }
130 
dump(PrintWriter pw)131     public void dump(PrintWriter pw) {
132         pw.print("{old="); pw.print(mOldRotation); pw.print(", new="); pw.print(mNewRotation);
133         pw.print("}");
134     }
135 
136     @Override
toString()137     public String toString() {
138         StringWriter sw = new StringWriter();
139         dump(new PrintWriter(sw));
140         return "ForcedSeamlessRotator" + sw.toString();
141     }
142 }
143