Launcher 桌面布局右侧不满屏代码跟踪记录

平台:

RK3399 + Android8.1

屏幕分辨率: 1920x1080
DPI: 280

问题

Launcher及满屏APP, 显示时, 屏幕右边会显示不全, 不到边.

分调试信息:

Activity:

dumpsys activity
  mCurrentUser=0
  mLastStartReason=startHomeActivity: noMoreActivities resumeHomeStackTask:0:0
  mLastStartActivityTimeMs=Mar 28, 2019 7:01:58 AM
  mLastStartActivityResult=0
  mLastStartActivityRecord:
    packageName=com.android.launcher3 processName=com.android.launcher3
    launchedFromUid=0 launchedFromPackage=null userId=0
    app=ProcessRecord{59dbaa 1123:com.android.launcher3/u0a10}
    Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher }
    frontOfTask=true task=TaskRecord{221f42d #6 I=com.android.launcher3/.Launcher U=0 StackId=0 sz=1}
    taskAffinity=null
    realActivity=com.android.launcher3/.Launcher
    baseDir=/system/priv-app/Launcher3/Launcher3.apk
    dataDir=/data/user/0/com.android.launcher3
    stateNotNeeded=true componentSpecified=false mActivityType=1
    compat={280dpi always-compat} labelRes=0x7f0f000a icon=0x7f020015 theme=0x7f120002
    mLastReportedConfigurations:
     mGlobalConfig={1.0 ?mcc?mnc [en_US] ldltr sw617dp w1097dp h545dp 280dpi lrg long land -touch -keyb/v/h -nav/h appBounds=Rect(0, 0 - 1920, 996) s.4}
     mOverrideConfig={1.0 ?mcc?mnc [en_US] ldltr sw617dp w1058dp h545dp 280dpi lrg long land -touch -keyb/v/h -nav/h appBounds=Rect(0, 0 - 1853, 996) s.4}
    CurrentConfiguration={1.0 ?mcc?mnc [en_US] ldltr sw617dp w1058dp h545dp 280dpi lrg long land -touch -keyb/v/h -nav/h appBounds=Rect(0, 0 - 1853, 996) s.4}
    OverrideConfiguration={0.0 ?mcc?mnc ?localeList ?layoutDir sw617dp w1058dp h545dp ?density lrg long ?ldr ?wideColorGamut land ?uimode ?night ?touch ?keyb/?/? ?nav/? appBounds=Rect(0, 0 - 1853, 996)}
    mBounds=Rect(0, 0 - 1853, 996)
    taskDescription: iconFilename=null label="null" primaryColor=fff5f5f5
      backgroundColor=fffafafa
      statusBarColor=0
      navigationBarColor=0
    launchFailed=false launchCount=1 lastLaunchTime=-6m58s276ms
    haveState=false icicle=null
    state=RESUMED stopped=false delayedResume=false finishing=false
    keysPaused=false inHistory=true visible=true sleeping=false idle=true mStartingWindowState=STARTING_WINDOW_NOT_SHOWN
    fullscreen=true noDisplay=false immersive=false launchMode=2
    frozenBeforeDestroy=false forceNewConfig=false
    mActivityType=HOME_ACTIVITY_TYPE
    waitingVisible=false nowVisible=true lastVisibleTime=-6m57s484ms
    resizeMode=RESIZE_MODE_UNRESIZEABLE
    mLastReportedMultiWindowMode=false mLastReportedPictureInPictureMode=false
    maxAspectRatio=1.86
重点:OverrideConfiguration={0.0 ?mcc?mnc ?localeList ?layoutDir sw617dp w1058dp h545dp ?density lrg long ?ldr ?wideColorGamut land ?uimode ?night ?touch ?keyb/?/? ?nav/? appBounds=Rect(0, 0 - 1853, 996)}

Window:

dumpsys window:
  Window #6 Window{45072ec u0 com.android.launcher3/com.android.launcher3.Launcher}:
    mDisplayId=0 stackId=0 mSession=Session{c4723f9 1285:u0a10010} mClient=android.os.BinderProxy@e3fa19f
    mOwnerUid=10010 mShowToOwnerOnly=true package=com.android.launcher3 appop=NONE
    mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#20 ty=1 fl=#81910100 fmt=-2 wanim=0x10302f6 vsysui=0x700 needsMenuKey=2 colorMode=0}
    Requested w=1853 h=996 mLayoutSeq=185
    mHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false
    WindowStateAnimator{d2dce8f com.android.launcher3/com.android.launcher3.Launcher}:
      Surface: shown=true layer=21000 alpha=1.0 rect=(0.0,0.0) 1853.0 x 996.0 transform=(1.0, 0.0, 1.0, 0.0)
    mWallpaperX=0.0 mWallpaperY=0.5
    isOnScreen=true
    isVisible=true
rect=(0.0,0.0) 1853.0 x 996.0 transform=(1.0, 0.0, 1.0, 0.0)

源码点滴

|-- frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java

	private void updateOverrideConfiguration() {
        mTmpConfig.unset();
        computeBounds(mTmpBounds);
        if (mTmpBounds.equals(mBounds)) {
            return;
        }

        mBounds.set(mTmpBounds);
        // Bounds changed...update configuration to match.
        if (!mBounds.isEmpty()) {
            task.computeOverrideConfiguration(mTmpConfig, mBounds, null /* insetBounds */,
                    false /* overrideWidth */, false /* overrideHeight */);
        }
//更新了OverrideConfiguration.
        onOverrideConfigurationChanged(mTmpConfig);
    }
  
	/**
     * Computes the bounds to fit the Activity within the bounds of the {@link Configuration}.
     */
    // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
    private void computeBounds(Rect outBounds) {
        outBounds.setEmpty();
        final float maxAspectRatio = info.maxAspectRatio;
        final ActivityStack stack = getStack();
        if (task == null || stack == null || !task.mFullscreen || maxAspectRatio == 0
                || isInVrUiMode(getConfiguration())) {
            // We don't set override configuration if that activity task isn't fullscreen. I.e. the
            // activity is in multi-window mode. Or, there isn't a max aspect ratio specified for
            // the activity. This is indicated by an empty {@link outBounds}. We also don't set it
            // if we are in VR mode.
            return;
        }

        // We must base this on the parent configuration, because we set our override
        // configuration's appBounds based on the result of this method. If we used our own
        // configuration, it would be influenced by past invocations.
        final Configuration configuration = getParent().getConfiguration();
//1920
        final int containingAppWidth = configuration.appBounds.width();
//996
        final int containingAppHeight = configuration.appBounds.height();
        int maxActivityWidth = containingAppWidth;
        int maxActivityHeight = containingAppHeight;

        if (containingAppWidth < containingAppHeight) {
            // Width is the shorter side, so we use that to figure-out what the max. height
            // should be given the aspect ratio.
            maxActivityHeight = (int) ((maxActivityWidth * maxAspectRatio) + 0.5f);
        } else {
//当前是横屏, 所以走了这里.
//运算后, maxActivityWidth = 1853, 问题的原因就在这里.
            // Height is the shorter side, so we use that to figure-out what the max. width
            // should be given the aspect ratio.
            maxActivityWidth = (int) ((maxActivityHeight * maxAspectRatio) + 0.5f);
        }

        if (containingAppWidth <= maxActivityWidth && containingAppHeight <= maxActivityHeight) {
            // The display matches or is less than the activity aspect ratio, so nothing else to do.
            // Return the existing bounds. If this method is running for the first time,
            // {@link mBounds} will be empty (representing no override). If the method has run
            // before, then effect of {@link mBounds} will already have been applied to the
            // value returned from {@link getConfiguration}. Refer to
            // {@link TaskRecord#computeOverrideConfiguration}.
            outBounds.set(mBounds);
            return;
        }

        // Compute configuration based on max supported width and height.
        outBounds.set(0, 0, maxActivityWidth, maxActivityHeight);
        // Position the activity frame on the opposite side of the nav bar.
        final int navBarPosition = service.mWindowManager.getNavBarPosition();
        final int left = navBarPosition == NAV_BAR_LEFT
                ? configuration.appBounds.right - outBounds.width() : 0;
        outBounds.offsetTo(left, 0 /* top */);
    }

|-- frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

	final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {

			...
                // Because we could be starting an Activity in the system process this may not go
                // across a Binder interface which would create a new Configuration. Consequently
                // we have to always create a new Configuration here.

//OverrideConfiguration 会进一步传递到应用启动:
                final MergedConfiguration mergedConfiguration = new MergedConfiguration(
                        mService.getGlobalConfiguration(), r.getMergedOverrideConfiguration());
                r.setLastReportedConfiguration(mergedConfiguration);

                logIfTransactionTooLarge(r.intent, r.icicle);
                app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                        System.identityHashCode(r), r.info,
                        // TODO: Have this take the merged configuration instead of separate global
                        // and override configs.
                        mergedConfiguration.getGlobalConfiguration(),
                        mergedConfiguration.getOverrideConfiguration(), r.compat,
                        r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                        r.persistentState, results, newIntents, !andResume,
                        mService.isNextTransitionForward(), profilerInfo);
	}

|-- frameworks/base/core/java/android/app/ActivityThread.java

    private class ApplicationThread extends IApplicationThread.Stub {
		...

        // we use token to identify this activity without having to send the
        // activity itself back to the activity manager. (matters more with ipc)
        @Override
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

			...

//在前面Configuration:overrideConfig被重写, screenWidthDp 被1058
            r.overrideConfig = overrideConfig;
            updatePendingConfiguration(curConfig);

            sendMessage(H.LAUNCH_ACTIVITY, r);
        }
	        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
					...
			}


	private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
		...
        // Make sure we are running with the most recent config.
        handleConfigurationChanged(null, null);

        WindowManagerGlobal.initialize();
		Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
		...
	}
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
		...
//创建了 appContext
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
//创建Activity.
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            ...
        } catch (Exception e) {
			...
        }

        try {
//创建Application?
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
			...

            if (activity != null) {
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
//创建Configuration.
                Configuration config = new Configuration(mCompatConfiguration);
                if (r.overrideConfig != null) {
//覆盖Configuration
                    config.updateFrom(r.overrideConfig);
                }
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                Window window = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                appContext.setOuterContext(activity);
//调用attach, 传入appContext, 创建PhoneWindow
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);

//...省略Activity启动的生命周期调用代码.

            mActivities.put(r.token, r);
    }

    final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
		...
//添加根View到WindowManager
                if (a.mVisibleFromClient) {
                    if (!a.mWindowAdded) {
                        a.mWindowAdded = true;
                        wm.addView(decor, l);
                    } else {
                        // The activity will get a callback for this {@link LayoutParams} change
                        // earlier. However, at that time the decor will not be set (this is set
                        // in this method), so no action will be taken. This call ensures the
                        // callback occurs with the decor set.
                        a.onWindowAttributesChanged(l);
                    }
                }
	}

mBase的赋值来自于Activity的调用:
|-- frameworks/base/core/java/android/app/Activity.java

    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback) {
        attachBaseContext(context);

        mFragments.attachHost(null /*parent*/);
//创建PhoneWindow
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
		...
		mCurrentConfig = config;

	}

|-- frameworks/base/core/java/android/app/Instrumentation.java

    /**
     * Perform instantiation of the process's {@link Activity} object.  The
     * default implementation provides the normal system behavior.
     * 
     * @param cl The ClassLoader with which to instantiate the object.
     * @param className The name of the class implementing the Activity
     *                  object.
     * @param intent The Intent object that specified the activity class being
     *               instantiated.
     * 
     * @return The newly instantiated Activity object.
     */
    public Activity newActivity(ClassLoader cl, String className,
            Intent intent)
            throws InstantiationException, IllegalAccessException,
            ClassNotFoundException {
        return (Activity)cl.loadClass(className).newInstance();
    }

|-- frameworks/base/core/java/android/view/WindowManagerImpl.java

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

|-- frameworks/base/core/java/android/view/WindowManagerGlobal.java

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
		...
            // do this last because it fires off messages to start doing things
            try {
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }

|-- frameworks/base/core/java/android/view/ViewRootImpl.java

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
			...
		}
	}
    private void performTraversals() {
        // cache mView since it is used so much below...
		...
        if (mFirst) {
            mFullRedrawNeeded = true;
            mLayoutRequested = true;

            final Configuration config = mContext.getResources().getConfiguration();
            if (shouldUseDisplaySize(lp)) {
                // NOTE -- system code, won't try to do compat mode.
                Point size = new Point();
                mDisplay.getRealSize(size);
                desiredWindowWidth = size.x;
                desiredWindowHeight = size.y;
            } else {
//config.screenWidthDp = 1058
                desiredWindowWidth = dipToPx(config.screenWidthDp);
                desiredWindowHeight = dipToPx(config.screenHeightDp);
            }
	}
    static class W extends IWindow.Stub {
		...
        @Override
        public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
                Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
                MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
                boolean alwaysConsumeNavBar, int displayId) {
            final ViewRootImpl viewAncestor = mViewAncestor.get();
            if (viewAncestor != null) {
                viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
                        visibleInsets, stableInsets, outsets, reportDraw, mergedConfiguration,
                        backDropFrame, forceLayout, alwaysConsumeNavBar, displayId);
            }
        }
	}
    private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
            Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
            MergedConfiguration mergedConfiguration, Rect backDropFrame, boolean forceLayout,
            boolean alwaysConsumeNavBar, int displayId) {
        ...
        Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT : MSG_RESIZED);
	}

    private int relayoutWindow(WindowManager.LayoutParams params, int viewVisibility,
            boolean insetsPending) throws RemoteException {

        float appScale = mAttachInfo.mApplicationScale;
        boolean restore = false;
        if (params != null && mTranslator != null) {
            restore = true;
            params.backup();
            mTranslator.translateWindowLayout(params);
        }
        if (params != null) {
            if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params);
        }

        //Log.d(mTag, ">>>>>> CALLING relayout");
        if (params != null && mOrigWindowType != params.type) {
            // For compatibility with old apps, don't crash here.
            if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                Slog.w(mTag, "Window type can not be changed after "
                        + "the window is added; ignoring change of " + mView);
                params.type = mOrigWindowType;
            }
        }

//获取出来的尺寸:
//mView.getMeasuredWidth(1852), mView.getMeasuredHeight(954), appScale(1.0)
        int relayoutResult = mWindowSession.relayout(
                mWindow, mSeq, params,
                (int) (mView.getMeasuredWidth() * appScale + 0.5f),
                (int) (mView.getMeasuredHeight() * appScale + 0.5f),
                viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0,
                mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets,
                mPendingStableInsets, mPendingOutsets, mPendingBackDropFrame,
                mPendingMergedConfiguration, mSurface);

        mPendingAlwaysConsumeNavBar =
                (relayoutResult & WindowManagerGlobal.RELAYOUT_RES_CONSUME_ALWAYS_NAV_BAR) != 0;

        //Log.d(mTag, "<<<<<< BACK FROM relayout");
        if (restore) {
            params.restore();
        }

        if (mTranslator != null) {
            mTranslator.translateRectInScreenToAppWinFrame(mWinFrame);
            mTranslator.translateRectInScreenToAppWindow(mPendingOverscanInsets);
            mTranslator.translateRectInScreenToAppWindow(mPendingContentInsets);
            mTranslator.translateRectInScreenToAppWindow(mPendingVisibleInsets);
            mTranslator.translateRectInScreenToAppWindow(mPendingStableInsets);
        }
        return relayoutResult;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值