Android 7.1 solves the problem of boot animation rotation

Description

The solution described herein has the particularity, targeted to be combined with the system currently implemented screen orientation setting scheme .
For reference do not mechanically

*There is no explanation of animation flow in this article, please move
*There is no explanation of the fixed screen orientation scheme in this article, please move

platform

RK3288 + Android 7.1

Overview

After the screen orientation is fixed, all displays are normal when the default is not rotated, but after rotating, the orientation of the boot animation display is either inaccurate or jumps.

premise

屏幕旋转方向有四个值, 分别为
Surface.ROTATION_0 (默认)
Surface.ROTATION_90
Surface.ROTATION_180
Surface.ROTATION_270

analysis

|-- frameworks/base/cmds/bootanimation/BootAnimation.cpp

BootAnimation::BootAnimation(bool shutdown) : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
        mTimeFormat12Hour(false), mTimeCheckThread(NULL) {
    
    
    mSession = new SurfaceComposerClient();

    // If the system has already booted, the animation is not being used for a boot.
    mSystemBoot = !property_get_bool(BOOT_COMPLETED_PROP_NAME, 0);
    mShutdown = shutdown;
    mReverseAxis = false;
    mVideoFile = NULL;
    mVideoAnimation = false;
    if(mShutdown){
    
    
        sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
                                        ISurfaceComposer::eDisplayIdMain)); // primary_display_token
        DisplayInfo dinfo;
        status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
        if (status == OK) {
    
    
            ALOGD("DISPLAY,W-H: %d-%d, ori: %d", dinfo.w, dinfo.h, dinfo.orientation);
            if(dinfo.orientation==1 || dinfo.orientation==3 )
                mReverseAxis=true;
            else
                mReverseAxis=false;
        }
	}
}

The initial suspicion is that the screen rotation is causing the problem, so from the above code, the method of reading the screen information is extracted, and the information is printed out. The
code is in the loop of animation drawing

bool BootAnimation::android()
{
    
    
    //...
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

//加入打印显示信息代码
	 sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
                                        ISurfaceComposer::eDisplayIdMain)); // primary_display_token
     DisplayInfo dinfo;

    const nsecs_t startTime = systemTime();
    do {
    
    
//加入打印显示信息代码.
		status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
		if (status == OK) {
    
    
            ALOGD("DISPLAY,W-H: %d-%d, ori: %d", dinfo.w, dinfo.h, dinfo.orientation);
		}
		//...
        checkExit();
    } while (!exitPending());
}

LOG content is as follows:

01-03 01:17:31.965 327-376/? D/BootAnimation: DISPLAY,W-H: 1920-1080, ori: 0

The device on hand is 1920x1080 15.6-inch screen, the default is horizontal screen

When the fixed screen direction is rotated 90 degrees (vertical screen), the output LOG is:

2019-09-09 09:31:39.731 ? D/BootAnimation: DISPLAY,W-H: 1920-1080, ori: 0
//还有很多
2019-09-09 09:31:47.471 ? D/BootAnimation: DISPLAY,W-H: 1920-1080, ori: 1
//还有很多

Through observation, the rotation problem is indeed when the screen orientation changes. In addition, there is another problem. The first animation interface, the orientation is still the default 0-degree horizontal screen orientation.

In summary, there are two problems:

  1. The direction of the animation start interface is the default zero degree, which does not change with the system settings.
  2. During the animation startup process, it will rotate and cause the display content to be incomplete, as shown in the figure:
    Insert picture description here

Solve the animation start interface direction:

|-- frameworks/base/cmds/bootanimation/BootAnimation.cpp

BootAnimation::BootAnimation(bool shutdown) : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
        mTimeFormat12Hour(false), mTimeCheckThread(NULL) {
    
    
    mSession = new SurfaceComposerClient();

    // If the system has already booted, the animation is not being used for a boot.
    mSystemBoot = !property_get_bool(BOOT_COMPLETED_PROP_NAME, 0);
    mShutdown = shutdown;
    mReverseAxis = false;
    mVideoFile = NULL;
    mVideoAnimation = false;
//注释mShotdown判断, 启动时, 方向有可能设置为0以外的数值
    //if(mShutdown){
    
    
        sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
                                        ISurfaceComposer::eDisplayIdMain)); // primary_display_token
        DisplayInfo dinfo;
        status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
        if (status == OK) {
    
    
            ALOGD("DISPLAY,W-H: %d-%d, ori: %d", dinfo.w, dinfo.h, dinfo.orientation);

//解决启动时方向错误, 其中, 变量 rot根据需要的方向设置[0, 3];			
			int rot = 1;//90度
			if (rot >= 0) {
    
    
				int w = dinfo.w;
				int h = dinfo.h;
				if(rot == 1 || rot == 3){
    
    //竖屏时, xy轴需要对调
					mReverseAxis=true;
					h = dinfo.w;
					w = dinfo.h;
				}else{
    
    
					mReverseAxis=false;
				}

				Rect layerStackRect(w, h);
				Rect displayRect(0, 0, w, h);
				SurfaceComposerClient::setDisplayProjection(dtoken, rot, layerStackRect, displayRect);
			}

        }
    //}
}

status_t BootAnimation::readyToRun() {
    
    
    mAssets.addDefaultAssets();

    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
            ISurfaceComposer::eDisplayIdMain));
    DisplayInfo dinfo;
    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
    if (status)
        return -1;

    // create the native surface
    int curWidth = dinfo.w;
    int curHeight = dinfo.h;
//注释 mShutdown, 屏幕旋转不只发生在关机动画时.
    if(/*mShutdown && */mReverseAxis){
    
    
        curWidth = dinfo.h;
        curHeight = dinfo.w;
    }
//...省略代码
}

Solve the direction jump during the animation drawing process.

The LOG printed in the animation is as follows:

//启动正常
2019-09-09 10:41:20.662 ? D/BootAnimation: DISPLAY,W-H: 1920-1080, ori: 0
2019-09-09 10:41:20.818 ? D/BootAnimation: DISPLAY,W-H: 1920-1080, ori: 1
//省略

//到这时转回默认方向, 
2019-09-09 10:41:25.101 ? D/BootAnimation: DISPLAY,W-H: 1920-1080, ori: 0
//省略

//最后转回正常方向
2019-09-09 10:41:29.438 ? D/BootAnimation: DISPLAY,W-H: 1920-1080, ori: 1

|–frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

    private WindowManagerService(Context context, InputManagerService inputManager,
            boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {
    
    
		//... 省略代码
        // Add ourself to the Watchdog monitors.
        Watchdog.getInstance().addMonitor(this);

//设置默认旋转方向, 与动画的默认方向保持一致
		mRotation = Surface.ROTATION_90;

        SurfaceControl.openTransaction();
        try {
    
    
            createWatermarkInTransaction();
        } finally {
    
    
            SurfaceControl.closeTransaction();
        }

        showEmulatorDisplayOverlayIfNeeded();
    }

    /**
     * Updates the current rotation.
     *
     * Returns true if the rotation has been changed.  In this case YOU
     * MUST CALL sendNewConfiguration() TO UNFREEZE THE SCREEN.
     */
    public boolean updateRotationUncheckedLocked(boolean inTransaction) {
    
    
//省略大量代码
        if (DEBUG_ORIENTATION) {
    
    
            Slog.v(TAG_WM, "Selected orientation "
                    + mLastOrientation + ", got rotation " + rotation
                    + " which has " + (altOrientation ? "incompatible" : "compatible")
                    + " metrics");
        }
//保持默认方向
        /*if (mRotateOnBoot) {
             mRotation = Surface.ROTATION_0;
             rotation = Surface.ROTATION_90;
        }*/

        if (mRotation == rotation && mAltOrientation == altOrientation) {
    
    
            // No change.
             return false;
        }
//省略大量代码
	}

Relevant code records for screen switching:

There are multiple calls to the following processes, so be careful when analyzing

     com.android.server.wm.WindowManagerService.displayReady(WindowManagerService.java:8781)
     com.android.server.am.ActivityManagerService.updateConfiguration(ActivityManagerService.java:19241)
     com.android.server.am.ActivityManagerService.updateConfigurationLocked(ActivityManagerService.java:19255)
     com.android.server.am.ActivityManagerService.updateConfigurationLocked(ActivityManagerService.java:19261)
     com.android.server.am.ActivityManagerService.updateConfigurationLocked(ActivityManagerService.java:19393)
     com.android.server.wm.WindowManagerService.setNewConfiguration(WindowManagerService.java:4413)
     com.android.server.wm.WindowManagerService.onConfigurationChanged(WindowManagerService.java:4448)
     com.android.server.wm.WindowManagerService.reconfigureDisplayLocked(WindowManagerService.java:9952)
     com.android.server.wm.WindowManagerService.sendNewConfiguration(WindowManagerService.java:8035)
     com.android.server.am.ActivityManagerService.updateConfiguration(ActivityManagerService.java:19241)
     com.android.server.am.ActivityManagerService.updateConfigurationLocked(ActivityManagerService.java:19255)
     com.android.server.am.ActivityManagerService.updateConfigurationLocked(ActivityManagerService.java:19261)
     com.android.server.am.ActivityManagerService.updateConfigurationLocked(ActivityManagerService.java:19424)
     com.android.server.wm.WindowManagerService.continueSurfaceLayout(WindowManagerService.java:5957)
     com.android.server.wm.WindowSurfacePlacer.continueLayout(WindowSurfacePlacer.java:173)
     com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:184)
     com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:235)
     com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementInner(WindowSurfacePlacer.java:320)
     com.android.server.wm.WindowSurfacePlacer.applySurfaceChangesTransaction(WindowSurfacePlacer.java:884)
     com.android.server.display.DisplayManagerService$LocalService.performTraversalInTransactionFromWindowManager(DisplayManagerService.java:1671)
     com.android.server.display.DisplayManagerService.performTraversalInTransactionFromWindowManagerInternal(DisplayManagerService.java:338)
     com.android.server.display.DisplayManagerService.performTraversalInTransactionLocked(DisplayManagerService.java:892)
     com.android.server.display.DisplayManagerService.configureDisplayInTransactionLocked(DisplayManagerService.java:983)
     com.android.server.display.LogicalDisplay.configureDisplayInTransactionLocked(LogicalDisplay.java:426)
     com.android.server.display.DisplayDevice.setProjectionInTransactionLocked(DisplayDevice.java:194)
     com.android.server.display.DisplayDevice.setDisplayProjection()

Finally update the screen display:
frameworks/base/services/core/java/com/android/server/display/DisplayDevice.java

    /**
     * Sets the display projection while in a transaction.
     *
     * @param orientation defines the display's orientation
     * @param layerStackRect defines which area of the window manager coordinate
     *            space will be used
     * @param displayRect defines where on the display will layerStackRect be
     *            mapped to. displayRect is specified post-orientation, that is
     *            it uses the orientation seen by the end-user
     */
    public final void setProjectionInTransactionLocked(int orientation,
            Rect layerStackRect, Rect displayRect) {
    
    
        if (mCurrentOrientation != orientation
                || mCurrentLayerStackRect == null
                || !mCurrentLayerStackRect.equals(layerStackRect)
                || mCurrentDisplayRect == null
                || !mCurrentDisplayRect.equals(displayRect)) {
    
    
            mCurrentOrientation = orientation;

            if (mCurrentLayerStackRect == null) {
    
    
                mCurrentLayerStackRect = new Rect();
            }
            mCurrentLayerStackRect.set(layerStackRect);

            if (mCurrentDisplayRect == null) {
    
    
                mCurrentDisplayRect = new Rect();
            }
            mCurrentDisplayRect.set(displayRect);
//与Bootanimation中的函数类似
            SurfaceControl.setDisplayProjection(mDisplayToken,
                    orientation, layerStackRect, displayRect);
        }
    }

Guess you like

Origin blog.csdn.net/ansondroider/article/details/100655980