SystemUi quick-settings详解

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/xwdrhgr/article/details/102725699

com.android.systemui 包的内容具体如下

assist    帮助

dozn    休眠

keyboard    键盘

keyguard    键盘服务

media    媒体

net    网络

power    电源

qs    quick-settings    快速设置

recents    最近的活动

screenrecord    屏幕记录

screenshot    屏幕截图

settings    设置(例如:音量调节)

statuebar    状态栏

主要的是状态栏和快速设置,这两个是可以见的,也是修改的比较多的地方,我在网上查资料的时候看到一些不错的文章,拉过来分享一下。

在SystemUI中,状态栏和通知栏都是在PhoneStatusBar的makeStatusBarView方法添加进来的,这里主要说说状态栏中的QuickSettingPanel

[java] view plain copy

    // ================================================================================  

      // Constructing the view  

      // ================================================================================  

      protected PhoneStatusBarView makeStatusBarView() {  

          final Context context = mContext;  

      

          Resources res = context.getResources();  

      

          updateDisplaySize(); // populates mDisplayMetrics  

          updateResources();  

      

          mStatusBarWindow = (StatusBarWindowView) View.inflate(context,  

                  R.layout.super_status_bar, null);  

          ....  

      

          mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);  

          mStatusBarView.setBar(this);  

      

          PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);  

          mStatusBarView.setPanelHolder(holder);  

      

          mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(  

                  R.id.notification_panel);  

          mNotificationPanel.setStatusBar(this);  

      

      

      

          // Set up the quick settings tile panel  

          mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);  

          if (mQSPanel != null) {  

              final QSTileHost qsh = new QSTileHost(mContext, this,  

                      mBluetoothController, mLocationController, mRotationLockController,  

                      mNetworkController, mZenModeController, mHotspotController,  

                      mCastController, mFlashlightController,  

                      mUserSwitcherController, mKeyguardMonitor,  

                      mSecurityController);  

              mQSPanel.setHost(qsh);  

              mQSPanel.setTiles(qsh.getTiles());  

              mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);  

              mQSPanel.setBrightnessMirror(mBrightnessMirrorController);  

              mHeader.setQSPanel(mQSPanel);  

              qsh.setCallback(new QSTileHost.Callback() {  

                  @Override  

                  public void onTilesChanged() {  

                      mQSPanel.setTiles(qsh.getTiles());  

                  }  

              });  

          }  

          ....  

          return mStatusBarView;  

      }  

下面主要说下图中QuickSetting是什么显示出来以及图中的每个控件功能是何如实现的

具体图标对应的id在这就不一一说明了,可以自己对着上面的图去看,下面主要分析下这个界面是怎么显示出来的,在PhoneStatusBar的makeStatusBarView方法中加载了super_status_bar.xml文件

[java] view plain copy

    mStatusBarWindow = (StatusBarWindowView) View.inflate(context,  

            R.layout.super_status_bar, null);  

[html] view plain copy

    <com.android.systemui.statusbar.phone.StatusBarWindowView  

        xmlns:android="http://schemas.android.com/apk/res/android";  

        xmlns:sysui="http://schemas.android.com/apk/res-auto";  

        android:layout_width="match_parent"  

        android:layout_height="match_parent"  

        android:fitsSystemWindows="true">  

      

        ....  

      

        <include layout="@layout/status_bar"  

            android:layout_width="match_parent"  

            android:layout_height="@dimen/status_bar_height" />  

      

        <FrameLayout android:id="@+id/brightness_mirror"  

                     android:layout_width="@dimen/notification_panel_width"  

                     android:layout_height="wrap_content"  

                     android:layout_gravity="@integer/notification_panel_layout_gravity"  

                     android:paddingLeft="@dimen/notification_side_padding"  

                     android:paddingRight="@dimen/notification_side_padding"  

                     android:visibility="invisible">  

            <FrameLayout  

                    android:layout_width="match_parent"  

                    android:layout_height="match_parent"  

                    android:elevation="2dp"  

                    android:background="@drawable/brightness_mirror_background">  

                <include layout="@layout/quick_settings_brightness_dialog"  

                         android:layout_width="match_parent"  

                         android:layout_height="wrap_content" />  

            </FrameLayout>  

        </FrameLayout>  

      

        <com.android.systemui.statusbar.phone.PanelHolder  

            android:id="@+id/panel_holder"  

            android:layout_width="match_parent"  

            android:layout_height="match_parent"  

            android:background="@color/transparent" >  

            <include layout="@layout/status_bar_expanded"  

                android:layout_width="match_parent"  

                android:layout_height="match_parent"  

                android:visibility="gone" />  

        </com.android.systemui.statusbar.phone.PanelHolder>  

      

        ....  

      

    </com.android.systemui.statusbar.phone.StatusBarWindowView>  

在上面这个布局文件中include了status_bar_expanded.xml,在这个文件中差不多就包含了图中所有控件,其中qs_panel.xml主要包括亮度调节框及以下的那一块,status_bar_expanded_header主要是亮度调节框以上部分

[html] view plain copy

    <com.android.systemui.statusbar.phone.NotificationPanelView   

        xmlns:android="http://schemas.android.com/apk/res/android";  

        xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui";  

        android:id="@+id/notification_panel"  

        android:layout_width="match_parent"  

        android:layout_height="match_parent"  

        android:background="@android:color/transparent"  

        >  

        ....  

      

        <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer  

            android:layout_width="match_parent"  

            android:layout_height="match_parent"  

            android:layout_gravity="@integer/notification_panel_layout_gravity"  

            android:id="@+id/notification_container_parent"  

            android:clipToPadding="false"  

            android:clipChildren="false">  

      

            <com.android.systemui.statusbar.phone.ObservableScrollView  

                android:id="@+id/scroll_view"  

                android:layout_width="@dimen/notification_panel_width"  

                android:layout_height="match_parent"  

                android:layout_gravity="@integer/notification_panel_layout_gravity"  

                android:scrollbars="none"  

                android:overScrollMode="never"  

                android:fillViewport="true">  

                <LinearLayout  

                    android:layout_width="match_parent"  

                    android:layout_height="wrap_content"  

                    android:orientation="vertical">  

                    <include  

                        layout="@layout/qs_panel"  

                        android:layout_marginTop="@dimen/status_bar_header_height_expanded"  

                        android:layout_width="match_parent"  

                        android:layout_height="wrap_content"  

                        android:layout_marginLeft="@dimen/notification_side_padding"  

                        android:layout_marginRight="@dimen/notification_side_padding"/>  

      

                    <!-- A view to reserve space for the collapsed stack -->  

                    <!-- Layout height: notification_min_height + bottom_stack_peek_amount -->  

                    <View  

                        android:id="@+id/reserve_notification_space"  

                        android:layout_height="@dimen/min_stack_height"  

                        android:layout_width="match_parent"  

                        android:layout_marginTop="@dimen/notifications_top_padding" />  

      

                    <View  

                        android:layout_height="@dimen/notification_side_padding"  

                        android:layout_width="match_parent" />  

                </LinearLayout>  

            </com.android.systemui.statusbar.phone.ObservableScrollView>  

      

            <com.android.systemui.statusbar.stack.NotificationStackScrollLayout  

                android:id="@+id/notification_stack_scroller"  

                android:layout_width="@dimen/notification_panel_width"  

                android:layout_height="match_parent"  

                android:layout_gravity="@integer/notification_panel_layout_gravity"  

                android:layout_marginBottom="@dimen/close_handle_underlap"  

                android:importantForAccessibility="no" />  

      

            <ViewStub  

                android:id="@+id/keyguard_user_switcher"  

                android:layout="@layout/keyguard_user_switcher"  

                android:layout_height="match_parent"  

                android:layout_width="match_parent" />  

      

            <include  

                layout="@layout/keyguard_status_bar"  

                android:visibility="invisible" />  

      

        </com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer>  

      

        <include  

                layout="@layout/keyguard_bottom_area"  

                android:visibility="gone" />  

      

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

      

        ....  

      

    </com.android.systemui.statusbar.phone.NotificationPanelView>  

在这个布局中包含了status_bar_expanded_header.xml,下面具体看看status_bar_expanded_header这个布局文件,这个布局文件中主要包含了亮度调节框上面那一部分

看是不是有对应event事件被拦截了,导致控件本身的event事件没有响应到。

[java] view plain copy

    HotspotTile.java     

     @Override  

        protected void handleUpdateState(BooleanState state, Object arg) {  

            state.visible = mController.isHotspotSupported() && mUsageTracker.isRecentlyUsed();  

            state.label = mContext.getString(R.string.quick_settings_hotspot_label);  

      

            if (arg instanceof Boolean) {  

                state.value = (boolean) arg;  

            } else {  

                state.value = mController.isHotspotEnabled();  

            }  

            state.icon = state.visible && state.value ? mEnable : mDisable;  

        }  

[java] view plain copy

    ColorInversionTile.java  

        @Override  

        protected void handleUpdateState(BooleanState state, Object arg) {  

            final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();  

            final boolean enabled = value != 0;  

            state.visible = enabled || mUsageTracker.isRecentlyUsed();  

            state.value = enabled;  

            state.label = mContext.getString(R.string.quick_settings_inversion_label);  

            state.icon = enabled ? mEnable : mDisable;  

        }  

其它几个控件就不在详细说明了,可以对着第一张图看。另外提一点就是自己最近遇到的问题,亮度条不能拖动调节,只能点击调节。如果遇到通知栏里的控件不能click或move事件没有效果,可以在NotificationPanelView.java和PanelView.java的onInterceptTouchEvent和onTouchEvent中添加log,

[java] view plain copy

    @Override  

    protected void handleUpdateState(BooleanState state, Object arg) {  

        state.visible = mFlashlightController.isAvailable();  

        state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);  

        if (arg instanceof UserBoolean) {  

            boolean value = ((UserBoolean) arg).value;  

            if (value == state.value) {  

                return;  

            }  

            state.value = value;  

        } else {  

            state.value = mFlashlightController.isEnabled();  

        }  

        final AnimationIcon icon = state.value ? mEnable : mDisable;  

        icon.setAllowAnimation(arg instanceof UserBoolean && ((UserBoolean) arg).userInitiated);  

        state.icon = icon;  

        int onOrOffId = state.value  

                ? R.string.accessibility_quick_settings_flashlight_on  

                : R.string.accessibility_quick_settings_flashlight_off;  

        state.contentDescription = mContext.getString(onOrOffId);  

    }  

其中反色和热点两个图标会根据是不是最近使用过mUsageTracker.isRecentlyUsed(),来动态显示或隐藏

[java] view plain copy

    protected List<String> loadTileSpecs(String tileList) {  

        final Resources res = mContext.getResources();  

        final String defaultTileList = res.getString(R.string.quick_settings_tiles_default);  

        if (tileList == null) {  

            tileList = res.getString(R.string.quick_settings_tiles);  

            if (DEBUG) Log.d(TAG, "Loaded tile specs from config: " + tileList);  

        } else {  

            if (DEBUG) Log.d(TAG, "Loaded tile specs from setting: " + tileList);  

        }  

        final ArrayList<String> tiles = new ArrayList<String>();  

        boolean addedDefault = false;  

        for (String tile : tileList.split(",")) {  

            tile = tile.trim();  

            if (tile.isEmpty()) continue;  

            if (tile.equals("default")) {  

                if (!addedDefault) {  

                    tiles.addAll(Arrays.asList(defaultTileList.split(",")));  

                    addedDefault = true;  

                }  

            } else {  

                tiles.add(tile);  

            }  

        }  

        return tiles;  

    }  
[html] view plain copy

    <!-- The default tiles to display in QuickSettings -->  

    <string name="quick_settings_tiles_default" translatable="false">  

        wifi,bt,inversion,dnd,cell,airplane,rotation,flashlight,location,cast,hotspot  

    </string>  

只有配置了才可能会显示wifi,bt等这些图标,这些图标都对应着一个实体类,这些类都继承自QSTile<QSTile.BooleanState>,实际上是否显示都有这些实体类来决定的。比如flashlight对应着FlashlightTile.java,在handleUpdateState中会实时更新控件的状态,会根据mFlashlightController.isAvailable()的值,来决定是否显示闪光灯

[java] view plain copy

    public QSPanel(Context context, AttributeSet attrs) {  

        super(context, attrs);  

        mContext = context;  

      

        mDetail = LayoutInflater.from(context).inflate(R.layout.qs_detail, this, false);  

        mDetailContent = (ViewGroup) mDetail.findViewById(android.R.id.content);  

        mDetailSettingsButton = (TextView) mDetail.findViewById(android.R.id.button2);  

        mDetailDoneButton = (TextView) mDetail.findViewById(android.R.id.button1);  

        updateDetailText();  

        mDetail.setVisibility(GONE);  

        mDetail.setClickable(true);  

        mBrightnessView = LayoutInflater.from(context).inflate(  

                R.layout.quick_settings_brightness_dialog, this, false);  

        mFooter = new QSFooter(this, context);  

        addView(mDetail);  

        addView(mBrightnessView);  

        addView(mFooter.getView());  

        mClipper = new QSDetailClipper(mDetail);  

        updateResources();  

      

        mBrightnessController = new BrightnessController(getContext(),  

                (ImageView) findViewById(R.id.brightness_icon),  

                (ToggleSlider) findViewById(R.id.brightness_slider));  

[java] view plain copy

    // Set up the quick settings tile panel  

    mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);  

    if (mQSPanel != null) {  

        final QSTileHost qsh = new QSTileHost(mContext, this,  

                mBluetoothController, mLocationController, mRotationLockController,  

                mNetworkController, mZenModeController, mHotspotController,  

                mCastController, mFlashlightController,  

                mUserSwitcherController, mKeyguardMonitor,  

                mSecurityController);  

        mQSPanel.setHost(qsh);  

        mQSPanel.setTiles(qsh.getTiles());  

        mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);  

        mQSPanel.setBrightnessMirror(mBrightnessMirrorController);  

        mHeader.setQSPanel(mQSPanel);  

        qsh.setCallback(new QSTileHost.Callback() {  

            @Override  

            public void onTilesChanged() {  

                mQSPanel.setTiles(qsh.getTiles());  

            }  

        });  

    }  

在QSTileHost.java中会去加载默认配置需要显示的图标

[html] view plain copy

    <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:paddingTop="8dp"  

            android:paddingBottom="8dp"  

            android:elevation="2dp">  

      

        <com.android.systemui.qs.QSPanel  

                android:id="@+id/quick_settings_panel"  

                android:background="#0000"  

                android:layout_width="match_parent"  

                android:layout_height="wrap_content" />  

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

其中QSPanel是继承自ViewGroup的一个控件,里面包含了亮度调节框,以及wifi,蓝牙这些图标

[html] view plain copy

    <com.android.systemui.statusbar.phone.StatusBarHeaderView  

        xmlns:android="http://schemas.android.com/apk/res/android";  

        xmlns:systemui="http://schemas.android.com/apk/res-auto";  

        android:id="@+id/header"  

        android:layout_width="@dimen/notification_panel_width"  

        android:layout_height="@dimen/status_bar_header_height"  

        android:layout_gravity="@integer/notification_panel_layout_gravity"  

        android:paddingStart="@dimen/notification_side_padding"  

        android:paddingEnd="@dimen/notification_side_padding"  

        android:baselineAligned="false"  

        android:elevation="4dp"  

        android:background="@drawable/notification_header_bg"  

        android:clickable="true"  

        android:focusable="true"  

        >  

      

        <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"  

            android:layout_width="@dimen/multi_user_switch_width_collapsed"  

            android:layout_height="@dimen/status_bar_header_height"  

            android:layout_alignParentEnd="true"  

            android:background="@drawable/ripple_drawable" >  

            <ImageView android:id="@+id/multi_user_avatar"  

                android:layout_width="@dimen/multi_user_avatar_expanded_size"  

                android:layout_height="@dimen/multi_user_avatar_expanded_size"  

                android:layout_gravity="center"  

                android:scaleType="centerInside"/>  

        </com.android.systemui.statusbar.phone.MultiUserSwitch>  

      

        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout  

            android:id="@+id/settings_button_container"  

            android:layout_width="48dp"  

            android:layout_height="@dimen/status_bar_header_height"  

            android:clipChildren="false"  

            android:clipToPadding="false"  

            android:layout_toStartOf="@id/multi_user_switch">  

      

            <com.android.systemui.statusbar.phone.SettingsButton android:id="@+id/settings_button"  

                style="@android:style/Widget.Material.Button.Borderless"  

                android:layout_width="match_parent"  

                android:layout_height="match_parent"  

                android:background="@drawable/ripple_drawable"  

                android:src="@drawable/ic_settings"  

                android:contentDescription="@string/accessibility_desc_settings" />  

            <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/tuner_icon"  

                android:layout_width="match_parent"  

                android:layout_height="match_parent"  

                android:paddingStart="36dp"  

                android:tint="#4DFFFFFF"  

                android:tintMode="src_in"  

                android:visibility="invisible"  

                android:src="@drawable/tuner" />  

      

        </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>  

      

        <LinearLayout android:id="@+id/system_icons_super_container"  

            android:layout_width="wrap_content"  

            android:layout_height="@dimen/status_bar_header_height"  

            android:layout_toStartOf="@id/multi_user_switch"  

            android:layout_alignWithParentIfMissing="true"  

            android:layout_marginStart="16dp"  

            android:background="@drawable/ripple_drawable"  

            android:paddingEnd="4dp" >  

            <FrameLayout android:id="@+id/system_icons_container"  

                android:layout_width="wrap_content"  

                android:layout_height="@dimen/status_bar_height"  

                android:layout_gravity="center_vertical"  

                >  

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

            </FrameLayout>  

            <TextView android:id="@+id/battery_level"  

                android:layout_width="wrap_content"  

                android:layout_height="wrap_content"  

                android:layout_gravity="center_vertical"  

                android:layout_marginStart="@dimen/header_battery_margin_expanded"  

                android:paddingEnd="@dimen/battery_level_padding_end"  

                android:textColor="#ffffff"  

                android:textSize="@dimen/battery_level_text_size"  

                android:importantForAccessibility="noHideDescendants"/>  

        </LinearLayout>  

      

        <TextView  

            android:id="@+id/header_emergency_calls_only"  

            android:layout_height="@dimen/status_bar_header_height"  

            android:layout_width="wrap_content"  

            android:layout_alignParentStart="true"  

            android:layout_toStartOf="@id/system_icons_super_container"  

            android:paddingStart="16dp"  

            android:paddingEnd="16dp"  

            android:visibility="gone"  

            android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"  

            android:text="@*android:string/emergency_calls_only"  

            android:singleLine="true"  

            android:gravity="center_vertical" />  

      

        <FrameLayout  

            android:id="@+id/date_group"  

            android:layout_width="wrap_content"  

            android:layout_height="wrap_content"  

            android:layout_marginBottom="@dimen/clock_collapsed_bottom_margin"  

            android:layout_alignParentBottom="true">  

            <com.android.systemui.statusbar.policy.DateView android:id="@+id/date_collapsed"  

                android:layout_width="wrap_content"  

                android:layout_height="wrap_content"  

                android:layout_marginStart="16dp"  

                android:singleLine="true"  

                android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"  

                android:layout_below="@id/clock"  

                systemui:datePattern="@string/abbrev_wday_month_day_no_year_alarm"  

                />  

      

            <com.android.systemui.statusbar.policy.DateView android:id="@+id/date_expanded"  

                android:layout_width="wrap_content"  

                android:layout_height="wrap_content"  

                android:layout_marginStart="16dp"  

                android:singleLine="true"  

                android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"  

                android:layout_below="@id/clock"  

                systemui:datePattern="eeeeMMMMd"  

                />  

        </FrameLayout>  

      

        <include layout="@layout/split_clock_view"  

            android:layout_width="wrap_content"  

            android:layout_height="wrap_content"  

            android:layout_marginStart="16dp"  

            android:layout_above="@id/date_group"  

            android:id="@+id/clock"  

            />  

      

        <com.android.systemui.statusbar.AlphaOptimizedButton android:id="@+id/alarm_status"  

            android:layout_width="wrap_content"  

            android:layout_height="wrap_content"  

            android:layout_alignParentBottom="true"  

            android:layout_toEndOf="@id/date_group"  

            android:layout_marginBottom="4dp"  

            android:drawablePadding="6dp"  

            android:drawableStart="@drawable/ic_access_alarms_small"  

            android:textColor="#64ffffff"  

            android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"  

            android:paddingEnd="6dp"  

            android:paddingStart="6dp"  

            android:paddingTop="16dp"  

            android:paddingBottom="16dp"  

            android:background="?android:attr/selectableItemBackground"  

            android:visibility="gone"  

            />  

      

        <include  

            android:id="@+id/qs_detail_header"  

            layout="@layout/qs_detail_header"  

            android:layout_width="match_parent"  

            android:layout_height="wrap_content"  

            android:layout_alignParentBottom="true"  

            />  

      

        <com.android.systemui.statusbar.AlphaOptimizedImageView  

            android:id="@+id/qs_detail_header_progress"  

            android:src="@drawable/indeterminate_anim"  

            android:alpha="0"  

            android:background="@color/qs_detail_progress_track"  

            android:layout_width="match_parent"  

            android:layout_height="wrap_content"  

            android:layout_alignParentBottom="true"  

            systemui:hasOverlappingRendering="false"  

            />  

      

        <TextView  

            android:id="@+id/header_debug_info"  

            android:visibility="invisible"  

            android:layout_width="wrap_content"  

            android:layout_height="wrap_content"  

            android:layout_gravity="center_vertical"  

            android:fontFamily="sans-serif-condensed"  

            android:textSize="11dp"  

            android:textStyle="bold"  

            android:textColor="#00A040"  

            android:padding="2dp"  

            />  

      

    </com.android.systemui.statusbar.phone.StatusBarHeaderView>  

其余的控件差不多都在qs_panel.xml里了

猜你喜欢

转载自blog.csdn.net/xwdrhgr/article/details/102725699