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

简介: 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();
            i
相关文章
|
6月前
|
Windows
Keil5中恢复默认布局-解决左边栏,底部栏位置不是默认布局
Keil5中恢复默认布局-解决左边栏,底部栏位置不是默认布局
593 0
|
6月前
|
XML Java Android开发
Android Studio App开发之捕获屏幕的变更事件实战(包括竖屏与横屏切换,回到桌面与切换到任务列表)
Android Studio App开发之捕获屏幕的变更事件实战(包括竖屏与横屏切换,回到桌面与切换到任务列表)
198 0
|
6月前
|
定位技术 iOS开发
在地图页面,自动布局控件开始是隐藏或在屏幕外需要正常显示时再为正常的显示状态的,需要在显示之前加入
在地图页面,自动布局控件开始是隐藏或在屏幕外需要正常显示时再为正常的显示状态的,需要在显示之前加入
49 0
|
Android开发
Android 11 SystemUI(状态/导航栏)-状态栏下拉时图标的隐藏与通知面板的半透黑色背景
Android 11 SystemUI(状态/导航栏)-状态栏下拉时图标的隐藏与通知面板的半透黑色背景
859 0
Android 11 SystemUI(状态/导航栏)-状态栏下拉时图标的隐藏与通知面板的半透黑色背景
|
存储 XML 缓存
Android 天气APP(十三)仿微信弹窗(右上角加号点击弹窗效果)、自定义背景图片、UI优化调整
Android 天气APP(十三)仿微信弹窗(右上角加号点击弹窗效果)、自定义背景图片、UI优化调整
209 0
Android 天气APP(十三)仿微信弹窗(右上角加号点击弹窗效果)、自定义背景图片、UI优化调整
|
Android开发
Android 10.0 顶部状态栏系统图标显示分析
Android 10.0 顶部状态栏系统图标显示分析
|
Web App开发 iOS开发
为 iPhone 和 iPad 自定义网站的主屏幕图标
iPhone 和 iPad 等苹果设备使用主屏幕 (Home Screen, 也称桌面) 管理应用程序, 还可以通过浏览器的添加到主屏幕功能将网站链接作为快捷方式添加为主屏幕图标. 是否你也想过为网站定义一个图标, 如果用户将网站添加至主屏幕, 网站链接看起来更像原生程序, 也能获得更多的关注.
1501 0
|
缓存 Android开发
解决bug:Android 更换新logo图标后,运行项目图标没有变化
解决bug:Android 更换新logo图标后,运行项目图标没有变化
609 0
|
调度 Windows
Mac 技术篇-触发角功能设置一步回到桌面、快速锁屏、展示启动图应用列表
Mac 技术篇-触发角功能设置一步回到桌面、快速锁屏、展示启动图应用列表
179 0
Mac 技术篇-触发角功能设置一步回到桌面、快速锁屏、展示启动图应用列表