Android 6.0 Marshmallow 通知栏中QuickSetting分析

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

  // ================================================================================
    // 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是什么显示出来以及图中的每个控件功能是何如实现的

Android 6.0 Marshmallow 通知栏中QuickSetting分析_第1张图片

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


        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                R.layout.super_status_bar, null);


    ....

    

    
        
            
        
    

    
        
    

    ....

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


    ....

    

        
            
                

                
                
                

                
            
        

        

        

        

    

    

    

    ....

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



    
        
    

    

        
        

    

    
        
            
        
        
    

    

    
        

        
    

    

    

    

    

    

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



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

    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));
        // 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中会去加载默认配置需要显示的图标

    protected List 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 tiles = new ArrayList();
        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;
    }
    
    
        wifi,bt,inversion,dnd,cell,airplane,rotation,flashlight,location,cast,hotspot
    
只有配置了才可能会显示wifi,bt等这些图标,这些图标都对应着一个实体类,这些类都继承自QSTile,实际上是否显示都有这些实体类来决定的。 比如flashlight对应着FlashlightTile.java,在handleUpdateState中会实时更新控件的状态,会根据mFlashlightController.isAvailable()的值,来决定是否显示闪光灯

    @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(),来动态显示或隐藏

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;
    }

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,
看是不是有对应event事件被拦截了,导致控件本身的event事件没有响应到。

你可能感兴趣的:(Android源码分析)