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

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

谢谢。

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

SystemUI源码分析四(QSPanel显示的流程)

quick settings是statusbar的一部分,随着statusbarview的创建而加载,上一篇SystemUI源码分析三中已经分析了statusbar的加载流程,那么这里将继续对其中的q...
  • qq_27215521
  • qq_27215521
  • 2017年03月17日 15:18
  • 1198

android6.0 SystemUI之快捷设置区域QSPanel及点击事件流程分析

SystemUI下拉之后的那些快捷设置菜单选项也是属于SystemUI的一种;它的加载也是随着PhoneStatusBar的加载而加载; 首先从布局方面入手: 快捷设置区域的布局是由Pho...
  • qq_33489669
  • qq_33489669
  • 2017年02月21日 19:36
  • 689

Android5.0 下拉通知栏快捷开关的添加(必看)

之前在开发的过程中修改了一些SystemUi相关的东西,今天就总结一下关于Android 5.0 下拉通知栏快捷按键的添加。 我们都知道,原生的Android5.0下拉菜单的图片是这样的:...
  • lyjIT
  • lyjIT
  • 2016年06月03日 16:42
  • 10887

关于systemui wifi图标更新过程分析

项目systemui没有wifi图标,我不知道是在布局还是代码中隐藏了还是没有接收到wifi更新通知,所以看了下wifi图标更新的过程,有些东西可能受水平的局限,分析得不是很到位 首先systemu...
  • MiTiHome
  • MiTiHome
  • 2016年10月21日 20:27
  • 975

关于android语言切换后通知栏显示的问题

改变android语言设置,但是状态栏的快捷功能显示文字不会立即发生改变。 同样,下拉通知栏的文字显示在切换语言后也不会同步更新。 于是在项目中引入: @SdkConstant(...
  • gwe_f
  • gwe_f
  • 2014年12月03日 22:38
  • 928

Android 7.0切换第一语言后下拉QuickSettings栏中的运营商名称不更新

平台:Android7.1.1 高通MSM8937 骁龙430 红米手机 一、现象 频繁切换语言后快速设置中的运营商名称(中国移动,中国联通,中国电信)不更新或者更新不及时。 二、分析 快速设置中的运...
  • guai8023
  • guai8023
  • 2017年04月20日 11:12
  • 1190

Android6.0 SystemUI之网络信号栏显示刷新

Android的网络信号栏的显示刷新也是SystemUI的一部分,主要业务逻辑也是在SystemUI这模块内的,整个流程的开始是在PhoneStatusBar.java内的, frameworks/...
  • Otaku_627
  • Otaku_627
  • 2016年12月13日 21:33
  • 3177

android 7.0 system UI之快速启动栏的分析(一)

作者:jason.chen  从状态栏往下拉的时候,就会出现“快速设置”界面,如下图所示。快速启动界面可以让用户快速设置和操作。对于急需或频繁使用的控件和操作,保留“快速设置”图块,且不应将其用作启动...
  • maetelibom
  • maetelibom
  • 2016年12月27日 15:43
  • 1772

android6.0 SystemUI之快捷设置区域QSPanel及点击事件流程分析

note:查看android源码可以访问https://github.com/android SystemUI下拉之后的那些快捷设置菜单选项也是属于SystemUI的一种;它的加载也是随着PhoneS...
  • Otaku_627
  • Otaku_627
  • 2016年12月11日 14:39
  • 2475

Android5.1禁止状态栏下拉(SystemUI StatusBar)

5.1状态栏要禁止下拉请按如下方案修改: PanelBar.java(alps\frameworks\base\packages\SystemUI\src\com\android\systemui...
  • wds1181977
  • wds1181977
  • 2016年09月09日 17:32
  • 2958
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:SystemUI下的快速设置面板显示异常
举报原因:
原因补充:

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