/*
|
* Copyright (C) 2018 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.server.wm;
|
|
import static android.view.Surface.ROTATION_270;
|
import static android.view.Surface.ROTATION_90;
|
|
import android.graphics.Matrix;
|
import android.view.DisplayInfo;
|
import android.view.Surface;
|
import android.view.Surface.Rotation;
|
import android.view.SurfaceControl.Transaction;
|
|
import com.android.server.wm.utils.CoordinateTransforms;
|
|
import java.io.PrintWriter;
|
import java.io.StringWriter;
|
|
/**
|
* Helper class for seamless rotation.
|
*
|
* Works by transforming the {@link WindowState} back into the old display rotation.
|
*
|
* Uses {@link android.view.SurfaceControl#deferTransactionUntil(Surface, long)} instead of
|
* latching on the buffer size to allow for seamless 180 degree rotations.
|
*/
|
public class SeamlessRotator {
|
|
private final Matrix mTransform = new Matrix();
|
private final float[] mFloat9 = new float[9];
|
private final int mOldRotation;
|
private final int mNewRotation;
|
|
public SeamlessRotator(@Rotation int oldRotation, @Rotation int newRotation, DisplayInfo info) {
|
mOldRotation = oldRotation;
|
mNewRotation = newRotation;
|
|
final boolean flipped = info.rotation == ROTATION_90 || info.rotation == ROTATION_270;
|
final int h = flipped ? info.logicalWidth : info.logicalHeight;
|
final int w = flipped ? info.logicalHeight : info.logicalWidth;
|
|
final Matrix tmp = new Matrix();
|
CoordinateTransforms.transformLogicalToPhysicalCoordinates(oldRotation, w, h, mTransform);
|
CoordinateTransforms.transformPhysicalToLogicalCoordinates(newRotation, w, h, tmp);
|
mTransform.postConcat(tmp);
|
}
|
|
/**
|
* Applies a transform to the {@link WindowState} surface that undoes the effect of the global
|
* display rotation.
|
*/
|
public void unrotate(Transaction transaction, WindowState win) {
|
transaction.setMatrix(win.getSurfaceControl(), mTransform, mFloat9);
|
|
// WindowState sets the position of the window so transform the position and update it.
|
final float[] winSurfacePos = {win.mLastSurfacePosition.x, win.mLastSurfacePosition.y};
|
mTransform.mapPoints(winSurfacePos);
|
transaction.setPosition(win.getSurfaceControl(), winSurfacePos[0], winSurfacePos[1]);
|
}
|
|
/**
|
* Returns the rotation of the display before it started rotating.
|
*
|
* @return the old rotation of the display
|
*/
|
@Rotation
|
public int getOldRotation() {
|
return mOldRotation;
|
}
|
|
/**
|
* Removes the transform and sets the previously known surface position for {@link WindowState}
|
* surface that undoes the effect of the global display rotation.
|
*
|
* Removing the transform and the result of the {@link WindowState} layout are both tied to the
|
* {@link WindowState} next frame, such that they apply at the same time the client draws the
|
* window in the new orientation.
|
*
|
* In the case of a rotation timeout, we want to remove the transform immediately and not defer
|
* it.
|
*/
|
public void finish(WindowState win, boolean timeout) {
|
mTransform.reset();
|
final Transaction t = win.getPendingTransaction();
|
t.setMatrix(win.mSurfaceControl, mTransform, mFloat9);
|
t.setPosition(win.mSurfaceControl, win.mLastSurfacePosition.x, win.mLastSurfacePosition.y);
|
if (win.mWinAnimator.mSurfaceController != null && !timeout) {
|
t.deferTransactionUntil(win.mSurfaceControl,
|
win.mWinAnimator.mSurfaceController.getHandle(), win.getFrameNumber());
|
t.deferTransactionUntil(win.mWinAnimator.mSurfaceController.mSurfaceControl,
|
win.mWinAnimator.mSurfaceController.getHandle(), win.getFrameNumber());
|
}
|
}
|
|
public void dump(PrintWriter pw) {
|
pw.print("{old="); pw.print(mOldRotation); pw.print(", new="); pw.print(mNewRotation);
|
pw.print("}");
|
}
|
|
@Override
|
public String toString() {
|
StringWriter sw = new StringWriter();
|
dump(new PrintWriter(sw));
|
return "ForcedSeamlessRotator" + sw.toString();
|
}
|
}
|