SystemUI下的快速设置面板显示异常

原创 2017年01月03日 11:04:58

前言:坚持自己能坚持的,成为自己想成为的,相信时间的累积是有效果的。

Step1复现

这个bug困扰了快一周了,今天终于突然来了灵感解决掉了,记录之。
测试:

General description: 
The notification bar display incorrect when edit quick settings. 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Reproducibility: 
10/10 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Precondition: 
Turn on auto-rotate 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Step: 
1.Homescreen->Settings->Display->Rotate dut to landscape mode->View->Display size->Change size then change to default size->Back to home screen->Rotate dut to portrait mode->Pull down notification bar->EDIT 
2.Check the screen display. 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Actual result: 
The notification bar display incorrect when edit quick settings. 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Expect result: 
The notification bar display correct when edit quick settings.

效果图如下:
这里写图片描述

Step2知识回顾

**A、横竖屏:**

通过这个bug的复现流程,横屏模式下设置 displaySize ,嗯,涉及到android横竖屏切换方面的知识,这方面的知识很薄弱,于是一边解bug一边网上查资料。感谢roserose0002Cynthia&Sky二位的精彩分析,下面我结合他们的博客做个自己的理解和学习。

当我们在清单文件中不添加关于横竖屏的配置信息时,横竖屏切换时会有一个Activity的销毁和重新创建的过程,一般的项目都会通过在清单文件中配置相关的信息通过执行onConfigureChanged方法来做一些处理。
即:

<uses-permission
 Android:name="android.permission.CHANGE_CONFIGURATION"></uses-permission>

允许改变配置信息,系统允许我们通过重写activity中的onConfigurationChanged方法来捕获和修改某些配置信息。

另外在我们想配置的相关的Activity需要添加一个节点

 <activity android:name=".recents.RecentsActivity"
                  android:label="@string/accessibility_desc_recent_apps"
                  android:exported="false"
                  android:launchMode="singleInstance"
                  android:excludeFromRecents="true"
                  android:stateNotNeeded="true"
                  android:resumeWhilePausing="true"
                  android:screenOrientation="behind"
                  android:resizeableActivity="true"
                  android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
                  android:theme="@style/RecentsTheme.Wallpaper">
            <intent-filter>
                <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
            </intent-filter>
        </activity>

它规定了可以再程序中捕获的事件类型。实际上它有这些字段
这里写图片描述

修改字体时会调用fontScale,修改display size会调用densityDpi。

B、页面和源代码的对应(MTK)
这个不是什么干货,相当于自己加深印象了,
a、在SystemUI下的qs文件夹下,QSPanel.java(View that represents the quick settings tile panel)

/** View that represents the quick settings tile panel. **/
public class QSPanel extends LinearLayout implements Tunable, Callback {
......
public QSPanel(Context context) {
        this(context, null);
    }

    public QSPanel(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;

        setOrientation(VERTICAL);

        mBrightnessView = LayoutInflater.from(context).inflate(
                R.layout.quick_settings_brightness_dialog, this, false);
        addView(mBrightnessView);

        mQuickSettingsPlugin = PluginManager.getQuickSettingsPlugin(mContext);
        mQuickSettingsPlugin.addOpViews(this);

        setupTileLayout();

        mFooter = new QSFooter(this, context);
        addView(mFooter.getView());

        updateResources();

        mBrightnessController = new BrightnessController(getContext(),
                (ImageView) findViewById(R.id.brightness_icon),
                (ToggleSlider) findViewById(R.id.brightness_slider));

    }
......
}

再看看哪里调用了这个控件,在Qs_panel.xml

<com.android.systemui.qs.QSContainer
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/quick_settings_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/qs_background_primary"
        android:clipToPadding="false"
        android:clipChildren="false"
        android:elevation="4dp">

    <com.android.systemui.qs.QSPanel
            android:id="@+id/quick_settings_panel"
            android:background="#0000"
            android:layout_marginTop="@dimen/status_bar_header_height"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingBottom="8dp" />

    <include layout="@layout/quick_status_bar_expanded_header" />

    <include android:id="@+id/qs_detail" layout="@layout/qs_detail" />

    <include android:id="@+id/qs_customize" layout="@layout/qs_customize_panel"
        android:visibility="gone" />

</com.android.systemui.qs.QSContainer>

QSPanel属于QSContainer的子控件。效果图是这样的:
这里写图片描述
QSPanel,点击edit

  mEditText = (TextView) findViewById(android.R.id.edit);
        mEditText.setOnClickListener(view ->
                mHost.startRunnableDismissingKeyguard(() -> showEdit(view)));
private void showEdit(final View v) {
        v.post(new Runnable() {
            @Override
            public void run() {
                if (mCustomizePanel != null) {
                    if (!mCustomizePanel.isCustomizing()) {
                        int[] loc = new int[2];
                        v.getLocationInWindow(loc);
                        int x = loc[0];
                        int y = loc[1];
                        mCustomizePanel.show(x, y);
                    }
                }

            }
        });
    }

执行mCustomizePanel.show(x, y);方法,这个类的描述是

/**
 * Allows full-screen customization of QS, through show() and hide().
 *
 * This adds itself to the status bar window, so it can appear on top of quick settings and
 * *someday* do fancy animations to get into/out of it.

show 或者 hide详情,是不是这个类的configuration变化,导致quicksetting显示异常

 protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        View navBackdrop = findViewById(R.id.nav_bar_background);
        if (navBackdrop != null) {
            boolean shouldShow = newConfig.smallestScreenWidthDp >= 600
                    || newConfig.orientation != Configuration.ORIENTATION_LANDSCAPE;
            navBackdrop.setVisibility(shouldShow ? View.VISIBLE : View.GONE);
        }
    }

事实上QSCustomizer.java的这个方法比较简单,就是在实现父类的同时加上了自己navBackdrop 视图。
在这里里面我尝试reloadwitdth是没用的

private void reloadWidth(View view) {
        LayoutParams params = (LayoutParams) view.getLayoutParams();
        params.width = getContext().getResources().getDimensionPixelSize(
                R.dimen.notification_panel_width);
        view.setLayoutParams(params);
    }

Step3 找源头

偶然发现了这个类

/**
 * Custom {@link FrameLayout} that re-inflates when changes to {@link Configuration} happen.
 * Currently supports changes to density and locale.
 */
public class AutoReinflateContainer extends FrameLayout {
......
  @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        boolean shouldInflateLayout = false;
        final int density = newConfig.densityDpi;
        if (density != mDensity) {
            mDensity = density;
            shouldInflateLayout = true;
        }
        final LocaleList localeList = newConfig.getLocales();
        if (localeList != mLocaleList) {
            mLocaleList = localeList;
            shouldInflateLayout = true;
        }

        if (shouldInflateLayout) {
            inflateLayout();
        }
    }

    private void inflateLayout() {
        removeAllViews();
        LayoutInflater.from(getContext()).inflate(mLayout, this);
        final int N = mInflateListeners.size();
        for (int i = 0; i < N; i++) {
            mInflateListeners.get(i).onInflated(getChildAt(0));
        }
    }

......
}

当density 和locale变化时会重新加载view,所以我强行的去掉if,只要配置信息变化就加在view,这个是治标不治本的。

// if (shouldInflateLayout) {
            inflateLayout();
      //  }

至于为什么横屏切换时导致计算错误还要进一步找原因。
最终的图是这样的这里写图片描述

谢谢。

版权声明:欢迎转载,开源大法好

相关文章推荐

Android Configuration change引发的问题及解决方法

之前在学习Fragment和总结Android异步操作的时候会在很多blog中看到对Configuration Change的讨论,以前做的项目都是固定竖屏的,所以对横竖屏切换以及横竖屏切换对程序有什...

Android 7.0 SystemUI 之启动和状态栏和导航栏简介

Android 7.0 SystemUI 之启动和状态栏和导航栏简介一、SystemUI 是什么首先SystemUI 是一个系统应用,apk路径位于/system/priv-app源码路径位于:/fr...

SystemUI初始化加载流程

1.1System启动,ActivityManagerService在systemReady时启动SystemUIService:   frameworks\base\services\java\co...

Android SystemUI 的一些主要操作

这里 Android SystemUI 主要是指ActionBar, 顶部的状态栏和底部的导航栏,图片壁纸和 RecentPanel 不在本文的谈论范围之内;一、 ActitonBar严格来说, Ac...

Android源代码在长按home键添加一键清除当前任务

主要修改一个布局文件:/frameworks/base/packages/SystemUI/res/layout/status_bar_recent_panel.xml 一个java文件:/frame...

设置按下电源立刻锁屏失败

bug描述“General description: It needs about 1s to lock screen when press power key again to awake ph...

SystemUI新增快捷方式

以网格快捷设置栏为例,在makeStatusBarView()方法中 mQS = new QuickSettingsController(mContext, mSet...

SystemUI下拉通知栏和下拉快捷设置栏的对应设置

根据SystemUI下的PanelView,他就是下拉通知栏和下拉快捷设置栏所继承的父类,这里面实现了下拉的动作监听,即是对status bar最下面那根横线的监听,当对她进行OnTouch时间时,判...

android 6.0 SystemUI源码分析(4)-StatusBar显示流程

android 6.0 SystemUI源码分析(4)-StatusBar显示流程 转载 http://blog.csdn.net/zhudaozhuan/article/details/50829...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:SystemUI下的快速设置面板显示异常
举报原因:
原因补充:

(最多只允许输入30个字)