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

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

        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
                R.layout.super_status_bar, null);
<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主要是亮度调节框以上部分
<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这个布局文件,这个布局文件中主要包含了亮度调节框上面那一部分
<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里了
<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,蓝牙这些图标
    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<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;
    }
    <!-- 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()的值,来决定是否显示闪光灯
    @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事件没有响应到。
  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
要下载Android 6.0 SDK的全集,您可以按照以下步骤操作: 首先,确保您的计算机已连接互联网,并具备良好的网络连接。 然后,打开您的浏览器,并在搜索引擎输入“Android 6.0 SDK全集下载”。点击搜索按钮,以获取相关的结果。 在搜索结果,您将看到多个网站提供Android SDK的下载。尽量选择可信赖和权威的网站,例如Google官方网站、Android Developer官方网站、GitHub等。 在选定的网站上,浏览下载页面,找到适用于Android 6.0 Marshmallow的SDK全集下载链接。点击下载链接,并根据网站要求进行登录或其他验证操作。 接下来,选择合适的下载方式,例如ZIP压缩包或EXE可执行文件,然后保存该文件到您的计算机本地目录。确保目录路径不包含文或其他特殊字符,以避免出现下载或安装问题。 下载完成后,打开保存的文件,并按照安装向导的指示完成SDK的安装过程。一般情况下,安装向导会要求您选择安装目录和其他相关设置。 等待安装程序完成,然后打开Android开发工具,例如Android Studio或Eclipse。在开发工具的设置,指定安装的Android 6.0 SDK路径。 下载和安装完成后,您就可以开始在Android 6.0 Marshmallow平台上进行开发和测试了。 总结起来,要下载Android 6.0 SDK的全集,您需要通过可信赖的网站下载安装文件,并按照安装向导的指引完成安装过程。完成后,您就可以开始使用Android 6.0 SDK进行应用程序的开发和测试了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值