返回

屏幕方向与显示方向的确定

Android

Android R WindowManagerService模块(7)屏幕旋转流程(2)

接上篇文章的内容,屏幕旋转的第一步便是需要根据获取的屏幕方向值和当前窗口的属性确定该窗口的显示方向。

屏幕方向值的获取方法在上一篇文章中已经进行了详细的介绍,屏幕的旋转方向共有五种,分别为:ROTATION_0、ROTATION_90、ROTATION_180、ROTATION_270、ROTATION_FREEZE。

而当前窗口的属性则包括了window的各种属性信息,例如window的宽高、位置、类型、透明度等等。

针对不同的屏幕方向值和不同的窗口属性,需要确定不同的显示方向,以确保窗口在屏幕上以正确的方式显示。

void updateDisplaySizeAndRotationLocked() {
    mPolicy.setRotation(mDisplay.getDisplayId(), displayPolicy.getRotation());
    setSystemUiOrientation();
    updateRotationLocked();
}

确定显示方向需要经过一系列的步骤,首先是调用updateDisplaySizeAndRotationLocked()方法,该方法主要做了两件事:一是调用mPolicy.setRotation()方法设置屏幕方向;二是调用setSystemUiOrientation()方法设置SystemUI的方向。

void setSystemUiOrientation() {
    SystemProperties.set("sys.display_rotation",
            Integer.toString(mDisplay.getDisplayId()) + ":"
                    + Integer.toString(mDisplay.getRotation()));
}

setSystemUiOrientation()方法的作用是设置SystemUI的方向,其中SystemProperties.set()方法用于设置系统属性。

void updateRotationLocked() {
    for (int i = 0; i < mLooperHooks.size(); i++) {
        LooperHook loopHook = mLooperHooks.get(i);
        if (Looper.myLooper() == loopHook.mLooper) {
            loopHook.updateRotationLocked();
            return;
        }
    }
}

updateRotationLocked()方法用于更新屏幕方向,它遍历mLooperHooks列表,找到与当前线程关联的LooperHook,并调用其updateRotationLocked()方法来更新屏幕方向。

void updateRotationLocked() {
    if (mLooper == null) {
        return;
    }
    if (mRotationNeedsRelayout) {
        mLooper.requestLayout();
        mRotationNeedsRelayout = false;
    } else {
        mLooper.dispatchRotationAnimationStart();
        mLooper.dispatchRotationAnimationEnd();
    }
}

LooperHook的updateRotationLocked()方法会根据需要进行重新布局或分派旋转动画。

除了设置显示方向之外,屏幕旋转还需要更新逻辑屏方向。

逻辑屏方向是指应用程序认为的屏幕方向,它与显示方向并不一定相同。

例如,对于一款横屏游戏,即使屏幕的方向是竖屏,但游戏仍然可以以横屏的方式显示。

void startRotationAnimationLocked(int toRotation, boolean enter) {
    mDisplayRotation = toRotation;
    mRotationAnimating = true;
    scheduleAnimationLocked();
    mFrozenRotation = -1;
    orientationChangedWhileAnimating = false;
}

startRotationAnimationLocked()方法用于启动屏幕旋转动画,它首先将mDisplayRotation设置为目标旋转角度,然后将mRotationAnimating设置为true,表示正在进行屏幕旋转动画。

void endRotationAnimationLocked() {
    mDisplayRotation = mFrozenRotation;
    mRotationAnimating = false;
    scheduleAnimationLocked();
    mFrozenRotation = -1;
}

endRotationAnimationLocked()方法用于结束屏幕旋转动画,它将mDisplayRotation设置为冻结的旋转角度,并将mRotationAnimating设置为false,表示屏幕旋转动画已结束。

屏幕旋转还需要进行转屏动画,转屏动画是指在屏幕旋转过程中显示的动画效果。

Android系统提供了两种类型的转屏动画:

  • 应用旋转动画: 由应用程序自己实现的动画效果。
  • 系统旋转动画: 由系统提供的默认动画效果。
boolean startRotationAnimationLocked(int toRotation, boolean enter, boolean forceDefault) {
    // ..
    if (mAnimationEnabled) {
        if (!forceDefault) {
            // Give the application a chance to handle the rotation first.
            if (sendRotationAnimationSpecLocked(toRotation, enter)) {
                // Application handled the rotation animation itself.
                return true;
            }
        }
        // No application rotation animation.  Use the system default.
        mLooper.dispatchRotationAnimationStart();
        mLooper.dispatchRotationAnimationEnd();
    }
    // ..
}

startRotationAnimationLocked()方法会先尝试让应用程序处理转屏动画,如果应用程序没有处理,则使用系统的默认动画效果。

系统默认的转屏动画效果是由SurfaceFlinger实现的,它支持以下几种类型的动画效果:

  • 渐隐渐现: 窗口从一个方向渐隐,然后在另一个方向渐现。
  • 缩放: 窗口从一个方向缩放到另一个方向。
  • 滑动: 窗口从一个方向滑动到另一个方向。

具体使用哪种动画效果是由系统根据窗口的属性和屏幕方向值来决定的。