Android 9.0系统源码_SystemUI(五)QuickSettings的创建

前言

前面几篇文章简单介绍了系统状态栏的创建,也介绍了状态栏图标控制器和通知栏图标控制器。本篇文章我们继续来分析SystemUI另一个模块Quick Settings。

Quick Settings视图
该功能位于下拉的通知面板中,在用户单手指下拉通知面板的时候,Quick Settings区域显示成一个长条,用户可以点击右上角的尖号展开这个区域。

Quick Settings提供给用户非常便捷的按钮,用户甚至无需解锁就可以操作这个区域,通过点击Quick Settings中的Tile来切换某个功能的状态,例如打开/关闭手电筒,蓝牙,Wifi等功能。这对于用户来说是非常便捷的。

一、开发者API

使用Quick Settings功能非常的简单,只需要与Tile和TileService两个类打交道即可。它们的类图如下图所示:

TileService是android.app.Service的子类,开发者通过继承TileService并覆写其对应的方法来完成功能的实现。TileService中提供的状态回调方法如下:

方法名 说明
onClick() 当前Tile被点击了
onDestroy() 当前Tile将要被销毁
onStartListening() 当前Tile将要进入监听状态
onStopListening() 当前Tile将要退出监听状态
onTileAdded() 当前Tile被添加到Quick Settings中
onTileRemoved() 当前Tile被从Quick Settings中删除

在这些状态变更的时候,开发者可以根据状态的不同来调整Tile的状态。调整的方法就是:先通过TileService.getQsTile()获取到当前Tile,然后通过Tile的setXXX方法来修改。最后调用Tile.updateTile()来使刚刚的设置生效。

下面是一段代码示例。这段代码的功能是根据用户点击来将Tile在Active和非Active状态之间进行切换。

二、QSTileHost

首先介绍一个类QSTileHost,从名字你应该就知道这个类的用途。

frameworks/base/packages/SystemUI/src/com/android/systemui/qs/QSTileHost.java

private static final String SERVICE_STATUS_FLAG = "serviceStatus";
private static final String PREFERENCES_KEY = 
    "com.google.android_quick_settings";

@Override
public void onClick() {Log.d("QS", "Tile tapped");
    updateTile();
}

// Changes the appearance of the tile.
private void updateTile() {

    Tile tile = this.getQsTile();boolean isActive = getServiceStatus();

    Icon newIcon;
    String newLabel;
    int newState;

    // Change the tile to match the service status.
    if (isActive) {

        newLabel = String.format(Locale.US,
                       "%s %s",
                       getString(R.string.tile_label),
                       getString(R.string.service_active));

        newIcon = Icon.createWithResource(getApplicationContext(),
                      R.drawable.ic_android_black_24dp);

        newState = Tile.STATE_ACTIVE;

    } else {
        newLabel = String.format(Locale.US,
                "%s %s",
                getString(R.string.tile_label),
                getString(R.string.service_inactive));

        newIcon =
                Icon.createWithResource(getApplicationContext(),
                        android.R.drawable.ic_dialog_alert);

        newState = Tile.STATE_INACTIVE;
    }

    // Change the UI of the tile.
    tile.setLabel(newLabel); ③
    tile.setIcon(newIcon);
    tile.setState(newState);

    // Need to call updateTile for the tile to pick up changes.
    tile.updateTile();}

这段代码说明如下:

处理用户的点击事件
获取自身的Tile对象
设置Tile的状态,包括:Label,Icon,State
设置完成之后真正让状态生效
在实现完成这个TileService之后,我们还需要将其注册到Manifest中。TileService需要设置一个特殊的权限和Intent-Filter的Action,如下所示:

<service
    android:name=".QuickSettingsService"
    android:icon="@drawable/ic_android_black_dp"
    android:label="@string/tile_label"
    android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
    <intent-filter>
        <action android:name="android.service.quicksettings.action.QS_TILE" />
    </intent-filter>
</service>

当我们将包含这个TileService的应用安装到设备上之后,下划通知面板然后展开Quick Settings区域便可以看到我们开发的Tile了。

系统实现
我们可以通过前面提到的Layout Inspector工具来分析Quick Settings的结构。

Quick Settings位于下拉的通知面板中。在布局上,这个部分通过QSContainer作为外部的容器,其中包含了一个QSPanel。

QSPanel中,包含了一个调节屏幕亮度的控件,这是通过一个LinearLayout来进行布局的,接下来就是PagedTileLayout中包含的多个Tile了,每个Tile用一个QSTileView来进行布局。PagedTileLayout正如其名称所示,这是一个可以分页的Layout。

QSContainer中包含的元素如下图所示:
在这里插入图片描述
在Android系统中,包含两类Tile:

一类是系统预置的
另一类的第三方应用中包含的
Quick Settings功能实现主要位于这个目录中: /frameworks/base/packages/SystemUI/src/com/android/systemui/qs。

系统预置Tile
qs目录下,包含了布局结构中用到的几个元素的实现类,包括:QSContainer,QSPanel,PagedTileLayout,QSTileView,QSIconView等。

系统本身包含了一些预装的Tile,例如:飞行模式的开关,位置信息的开关,热点功能的开关,手电筒功能开关等等。这些Tile的实现位于qs/tiles目录下,包含下面这些:

AirplaneModeTile.java
BatteryTile.java
BluetoothTile.java
CastTile.java
CellularTile.java
ColorInversionTile.java
DataSaverTile.java
DndTile.java
FlashlightTile.java
HotspotTile.java
IntentTile.java
LocationTile.java
NightDisplayTile.java
RotationLockTile.java
UserTile.java
WifiTile.java
WorkModeTile.java
在res目录下,有一个名称为quick_settings_tiles_stock的字符串列出了所有系统内置的Quick Setting的名称,它们通过逗号进行分隔。

<string name="quick_settings_tiles_stock" translatable="false">
wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night
</string>

QSTileHost中为这里的名称和实现类做了映射:

public QSTile<?> createTile(String tileSpec) {
   if (tileSpec.equals("wifi")) return new WifiTile(this);
   else if (tileSpec.equals("bt")) return new BluetoothTile(this);
   else if (tileSpec.equals("cell")) return new CellularTile(this);
   else if (tileSpec.equals("dnd")) return new DndTile(this);
   else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
   else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this);
   else if (tileSpec.equals("work")) return new WorkModeTile(this);
   else if (tileSpec.equals("rotation")) return new RotationLockTile(this);
   else if (tileSpec.equals("flashlight")) return new FlashlightTile(this);
   else if (tileSpec.equals("location")) return new LocationTile(this);
   else if (tileSpec.equals("cast")) return new CastTile(this);
   else if (tileSpec.equals("hotspot")) return new HotspotTile(this);
   else if (tileSpec.equals("user")) return new UserTile(this);
   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);
   // Intent tiles.
   else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
   else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec);
   else {
       Log.w(TAG, "Bad tile spec: " + tileSpec);
       return null;
   }
}

TileQueryHelper负责了Tile的初始化工作。在这个类中,会读取R.string.quick_settings_tiles_stock中的值,然后根据配置来初始化系统内置的Quick Setting:

// TileQueryHelper.java
String possible = mContext.getString(R.string.quick_settings_tiles_stock);
String[] possibleTiles = possible.split(",");
final Handler qsHandler = new Handler(host.getLooper());
final Handler mainHandler = new Handler(Looper.getMainLooper());
for (int i = 0; i < possibleTiles.length; i++) {
  final String spec = possibleTiles[i];
  final QSTile<?> tile = host.createTile(spec);
  if (tile == null || !tile.isAvailable()) {
      continue;
  }
  tile.setListening(this, true);
  tile.clearState();
  tile.refreshState();
  tile.setListening(this, false);
  qsHandler.post(new Runnable() {
      @Override
      public void run() {
          final QSTile.State state = tile.newTileState();
          tile.getState().copyTo(state);
          // Ignore the current state and get the generic label instead.
          state.label = tile.getTileLabel();
          mainHandler.post(new Runnable() {
              @Override
              public void run() {
                  addTile(spec, null, state, true);
                  mListener.onTilesChanged(mTiles);
              }
          });
      }
  });
}

这段代码应该很简单,这里就不多做说明了。
第三方应用中包含的Tile
对于SystemUI来说,除了要列出系统内置的Quick Setting之外,还有开发者开发的Quick Setting也需要读取。这部分逻辑通过QueryTilesTask以一个异步的Task来完成,这在这个异步任务中,会通过PackageManager查询所有开发者开发的Quick Setting

// TileQueryHelper.java
private class QueryTilesTask extends
       AsyncTask<Collection<QSTile<?>>, Void, Collection<TileInfo>> {
   @Override
   protected Collection<TileInfo> doInBackground(Collection<QSTile<?>>... params) {
       List<TileInfo> tiles = new ArrayList<>();
       PackageManager pm = mContext.getPackageManager();
       List<ResolveInfo> services = pm.queryIntentServicesAsUser(
               new Intent(TileService.ACTION_QS_TILE), 0, ActivityManager.getCurrentUser());String stockTiles = mContext.getString(R.string.quick_settings_tiles_stock);
       for (ResolveInfo info : services) {String packageName = info.serviceInfo.packageName;
           ComponentName componentName = new ComponentName(packageName, info.serviceInfo.name);

           // Don't include apps that are a part of the default tile set.
           if (stockTiles.contains(componentName.flattenToString())) {continue;
           }

           final CharSequence appLabel = info.serviceInfo.applicationInfo.loadLabel(pm);String spec = CustomTile.toSpec(componentName);
           State state = getState(params[0], spec);
           if (state != null) {
               addTile(spec, appLabel, state, false);
               continue;
           }
           if (info.serviceInfo.icon == 0 && info.serviceInfo.applicationInfo.icon == 0) {
               continue;
           }
           Drawable icon = info.serviceInfo.loadIcon(pm);
           if (!permission.BIND_QUICK_SETTINGS_TILE.equals(info.serviceInfo.permission)) {
               continue;
           }
           if (icon == null) {
               continue;
           }
           icon.mutate();
           icon.setTint(mContext.getColor(android.R.color.white));
           CharSequence label = info.serviceInfo.loadLabel(pm);
           addTile(spec, icon, label != null ? label.toString() : "null", appLabel, mContext);
       }
       return tiles;
   }

这段代码说明如下:

通过PackageManager查询所有设置了TileService.ACTION_QS_TILE的组件。PackageManager负责了所有应用包信息的管理。
遍历查询到的所有组件
跳过系统预置的Tile
为每个Tile读取标签和图标

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,我们可以了解到Android 9.0系统源码中SwipeHelper.java的位置为frameworks/base/packages/SystemUI/src/com/android/systemui/SwipeHelper.java。SwipeHelper.java是一个帮助类,用于处理滑动手势的事件。下面是SwipeHelper.java源码分析的流程: 1.首先,我们需要了解SwipeHelper.java的作用和功能。SwipeHelper.java是一个帮助类,用于处理滑动手势的事件。它可以检测用户的手势方向,并根据手势方向执行相应的操作。 2.接下来,我们需要了解SwipeHelper.java的主要方法和变量。SwipeHelper.java包含了一些重要的方法和变量,例如: - mSwipeDirection:表示滑动的方向,可以是上、下、左、右等方向。 - mSwipeThreshold:表示滑动的阈值,当用户滑动的距离超过这个阈值时,才会触发滑动事件。 - onInterceptTouchEvent:用于拦截触摸事件,判断是否需要处理滑动事件。 - onTouchEvent:用于处理触摸事件,根据手势方向执行相应的操作。 3.然后,我们需要了解SwipeHelper.java的具体实现。SwipeHelper.java主要实现了以下几个方法: - onInterceptTouchEvent:该方法用于拦截触摸事件,判断是否需要处理滑动事件。在该方法中,SwipeHelper会根据触摸事件的类型和位置,判断是否需要处理滑动事件。如果需要处理滑动事件,则返回true,否则返回false。 - onTouchEvent:该方法用于处理触摸事件,根据手势方向执行相应的操作。在该方法中,SwipeHelper会根据触摸事件的类型和位置,判断用户的手势方向,并根据手势方向执行相应的操作。例如,如果用户向左滑动,则会执行onSwipeLeft方法。 - onSwipeLeft:该方法用于处理向左滑动事件。在该方法中,SwipeHelper会执行一些操作,例如关闭通知栏、打开侧边栏等。 - onSwipeRight:该方法用于处理向右滑动事件。在该方法中,SwipeHelper会执行一些操作,例如打开通知栏、关闭侧边栏等。 - onSwipeUp:该方法用于处理向上滑动事件。在该方法中,SwipeHelper会执行一些操作,例如打开最近任务列表、打开应用程序列表等。 - onSwipeDown:该方法用于处理向下滑动事件。在该方法中,SwipeHelper会执行一些操作,例如关闭最近任务列表、关闭应用程序列表等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值