Android源码分析(十三)----SystemUI下拉状态栏如何添加快捷开关

一:如何添加快捷开关

源码路径:frameworks/base/packages/SystemUI/res/values/config.xml
添加headset快捷开关,参考如下修改。

Index: res/values/config.xml
===================================================================
--- res/values/config.xml	(版本 6870)
+++ res/values/config.xml	(工作副本)
@@ -101,7 +101,7 @@
     <!-- The default tiles to display in QuickSettings -->
     <!-- M: add hotknot tile -->
     <string name="quick_settings_tiles_default" translatable="false">
-        wifi,cell,battery,autobringht,custom(com.bullitt_group.night/nightsight.bullitt_group.com.night.quicksettings.QuickSettingsService),flashlight,dnd,rotation,bt,airplane,hotknot,nfc,location
+        wifi,cell,battery,autobringht,custom(com.bullitt_group.night/nightsight.bullitt_group.com.night.quicksettings.QuickSettingsService),flashlight,dnd,rotation,bt,airplane,hotknot,nfc,location,headset
     </string>
 
     <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->

Android版本7.1修改方式
源码路径:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
创建HeadsetTile 对象,实现快捷开关主要功能。

Index: src/com/android/systemui/statusbar/phone/QSTileHost.java
===================================================================
--- src/com/android/systemui/statusbar/phone/QSTileHost.java	(版本 6870)
+++ src/com/android/systemui/statusbar/phone/QSTileHost.java	(工作副本)
@@ -41,6 +41,7 @@
 import com.android.systemui.qs.external.TileLifecycleManager;
 import com.android.systemui.qs.external.TileServices;
 import com.android.systemui.qs.tiles.AirplaneModeTile;
+import com.android.systemui.qs.tiles.HeadsetTile;
 import com.android.systemui.qs.tiles.BatteryTile;
 import com.android.systemui.qs.tiles.BluetoothTile;
 import com.android.systemui.qs.tiles.CastTile;
@@ -501,6 +502,7 @@
         else if (tileSpec.equals("battery")) return new BatteryTile(this);
         else if (tileSpec.equals("saver")) return new DataSaverTile(this);
         else if (tileSpec.equals("night")) return new NightDisplayTile(this);
+        else if (tileSpec.equals("headset")) return new HeadsetTile(this);
 
         /// M: Add extra tiles in quicksetting @{
         else if (tileSpec.equals("hotknot") && SIMHelper.isMtkHotKnotSupport())

Android8.0修改方式,原理一样,只是代码路径不同,这里不做过多介绍。
源码路径:frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java

public class QSFactoryImpl implements QSFactory {

    private static final String TAG = "QSFactory";
    private final QSTileHost mHost;

    public QSFactoryImpl(QSTileHost host) {
        mHost = host;
    }   

    public QSTile createTile(String tileSpec) {
        if (tileSpec.equals("wifi")) return new WifiTile(mHost);
        else if (tileSpec.equals("bt")) return new BluetoothTile(mHost);
        else if (tileSpec.equals("cell")) return new CellularTile(mHost);
        else if (tileSpec.equals("dnd")) return new DndTile(mHost);
        else if (tileSpec.equals("inversion")) return new ColorInversionTile(mHost);
        else if (tileSpec.equals("airplane")) return new AirplaneModeTile(mHost);
        else if (tileSpec.equals("work")) return new WorkModeTile(mHost);
        else if (tileSpec.equals("rotation")) return new RotationLockTile(mHost);
        else if (tileSpec.equals("flashlight")) return new FlashlightTile(mHost);
        else if (tileSpec.equals("location")) return new LocationTile(mHost);
        else if (tileSpec.equals("cast")) return new CastTile(mHost);
        else if (tileSpec.equals("hotspot")) return new HotspotTile(mHost);
        else if (tileSpec.equals("user")) return new UserTile(mHost);
        else if (tileSpec.equals("battery")) return new BatterySaverTile(mHost);
        else if (tileSpec.equals("saver")) return new DataSaverTile(mHost);
        else if (tileSpec.equals("night")) return new NightDisplayTile(mHost);
        else if (tileSpec.equals("nfc")) return new NfcTile(mHost);
        // Intent tiles.
        else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(mHost, tileSpec);
        else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(mHost, tileSpec);
        else {
            Log.w(TAG, "Bad tile spec: " + tileSpec);
            return null;
        }   
    }  
二:快捷开关功能实现

这里主要实现,打开开关弹出Notification(不可删除通知),关闭开关才能关闭通知。
源码路径:frameworks/base/packages/SystemUI/src/com/android/systemui/qs/tiles/HeadsetTile.java

  1. 继承 QSTile<QSTile.BooleanState>
  2. newTileState方法中return new BooleanState()
  3. handleClick方法处理点击事件
  4. handleUpdateState方法更新状态信息
/* * Copyright (c) 2016, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */

package com.android.systemui.qs.tiles;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.util.Log;
import android.widget.Switch;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.SystemUI;
import com.android.systemui.qs.QSTile;


public class HeadsetTile extends QSTile<QSTile.BooleanState> {

    private Notification notification = new Notification();
    private NotificationManager mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    private boolean headsetState;

    public boolean isHeadsetState() {
        return headsetState;
    }

    public void setHeadsetState(boolean headsetState) {
        this.headsetState = headsetState;
    }

    public HeadsetTile(Host host) {
        super(host);
    }


    @Override
    public BooleanState newTileState() {
        return new BooleanState();
    }

    @Override
    protected void handleClick() {
        //default mState.value is false
        final boolean activated = !mState.value;
        Log.d("jasun", "========activated========" + activated);
        MetricsLogger.action(mContext, getMetricsCategory(), activated);
        if (activated == true) {
            SendNotification("Disable the headphone jack.");
            setHeadsetState(activated);
        } else {
            mNotificationManager.cancel(1);
            setHeadsetState(activated);
        }
        refreshState();
    }


    @Override
    protected void handleUpdateState(BooleanState state, Object arg) {
        final boolean isActivated = isHeadsetState();
        state.value = isActivated;
        state.label = mContext.getString(R.string.quick_settings_headset_label);
        state.icon = ResourceIcon.get(isActivated ? R.drawable.ic_qs_headset_on
                : R.drawable.ic_qs_headset_off);
        state.contentDescription = mContext.getString(isActivated
                ? R.string.quick_settings_headset_summary_on
                : R.string.quick_settings_headset_summary_off);
        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
                = Switch.class.getName();
    }

    @Override
    public int getMetricsCategory() {
        return MetricsEvent.QS_headset;
    }

    @Override
    public Intent getLongClickIntent() {
        return new Intent(Settings.ACTION_headset_SETTINGS);
    }

    @Override
    protected void setListening(boolean listening) {

    }

    private void sendNotification(String message) {
        Intent intent = new Intent(mContext, SystemUI.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,
                intent, 0);
        notification.icon = R.drawable.ic_qs_headset_on;
        notification.tickerText = "HeadSet can not used";
        notification.when = System.currentTimeMillis();
        notification.defaults = Notification.DEFAULT_SOUND
                | Notification.DEFAULT_VIBRATE;// set default sound
// notification.flags = Notification.FLAG_AUTO_CANCEL;// click auto disappeared
        notification.flags = Notification.FLAG_NO_CLEAR;
        notification.setLatestEventInfo(mContext, "Headset can not used", message, pendingIntent);

        mNotificationManager.notify(1, notification);

    }

    @Override
    public CharSequence getTileLabel() {
        return mContext.getString(R.string.quick_settings_headset_label);
    }
}

喜欢源码分析系列可参考其他文章:
Android源码分析(一)—–如何快速掌握Android编译文件
Android源码分析(二)—–如何编译修改后的framework资源文件
Android源码分析(三)—–系统框架设计思想
Android源码分析(四)—–Android源码编译及刷机步骤
Android源码分析(五)—–如何从架构师的角度去设计Framework框架

    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/LJX646566715/article/details/81989116
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞