Android 7.1 resuelve el problema de la rotación de la animación de arranque

Descripción

La solución descrita en el presente documento tiene la particularidad, específica para ser combinado con el sistema implementado actualmente esquema de ajuste de orientación de la pantalla .
Para referencia no hace mecánicamente

* No hay una explicación del flujo de animación en este artículo, muévalo
* No hay una explicación del esquema de orientación de la pantalla fija en este artículo, muévase

plataforma

RK3288 + Android 7.1

Visión de conjunto

Una vez que se fija la orientación de la pantalla, todas las pantallas son normales cuando el valor predeterminado no es girar, pero después de girar, la orientación de la pantalla de animación de inicio es inexacta o salta.

premisa

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

análisis

| - 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;
        }
	}
}

La sospecha inicial es que la rotación de la pantalla está causando el problema, por lo que a partir del código anterior, se extrae el método de lectura de la información de la pantalla y se imprime la información. El
código está en el bucle del dibujo de animación

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());
}

El contenido de LOG es el siguiente:

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

El dispositivo en la mano es una pantalla de 1920x1080 de 15,6 pulgadas, el valor predeterminado es la pantalla horizontal

Cuando la dirección de la pantalla fija se gira 90 grados (pantalla vertical), el LOG de salida es:

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
//还有很多

A través de la observación, el problema de rotación es de hecho cuando cambia la orientación de la pantalla. Además, hay otro problema. La primera interfaz de animación, la orientación sigue siendo la orientación horizontal predeterminada de la pantalla de 0 grados.

En resumen, hay dos problemas:

  1. La dirección de la interfaz de inicio de la animación es el cero grado predeterminado, que no cambia con la configuración del sistema.
  2. Durante el proceso de inicio de la animación, rotará y hará que el contenido de la pantalla esté incompleto, como se muestra en la figura:
    Inserte la descripción de la imagen aquí

Resuelva la dirección de la interfaz de inicio de la animación:

| - 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;
    }
//...省略代码
}

Resuelve el salto de dirección durante el proceso de dibujo de la animación.

El LOG impreso en la animación es el siguiente:

//启动正常
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;
        }
//省略大量代码
	}

Registros de códigos relevantes para el cambio de pantalla:

Hay varias llamadas a los siguientes procesos, así que tenga cuidado al analizar

     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()

Finalmente actualice la visualización de la pantalla:
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);
        }
    }

Supongo que te gusta

Origin blog.csdn.net/ansondroider/article/details/100655980
Recomendado
Clasificación