Android状态栏右侧添加图标并控制其显示状态

2024-08-21 10:08

本文主要是介绍Android状态栏右侧添加图标并控制其显示状态,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景介绍

最近接到一个需求。Android机器外接一个21key的键盘。键盘上有一个绿色和黄色按键。其功能就是当按下时,再按其他键会上报不同的键值。我们的外国合作伙伴就发现了一个问题,机器的页面上没有显示出按下绿键或者黄键的状态,就是说用户可能不知道当前键盘是在哪种输入状态。所以要求我们加上一个提示出来。

21key键盘
先看下最终效果,当按下绿色按键后,显示一个g字母,表示green的意思,黄色按键就是y,yellow。

g

思路

介绍完背景了,就讲一下实现过程吧。

其实刚开始我能想到的是直接加一个notification。但是!需求只是给用户个提示而已,notification不止在状态栏会显示在下拉菜单也会有个通知。这就有点杀鸡用牛刀的感觉。所以最好是在StatusBar右侧,电量图标旁边加上一个指示图标。

实现过程

本文是基于android P实现的,开始时候真的小看StatusBar了,以为会很简单,没想到一入源码深似海,进去半天出不来。不知道小伙伴们有没有用Hierarchy view看过StatusBar,它的Tree View就相当复杂。下面是电池图标的位置。是不是头皮发麻。

在这里插入图片描述

看了很多博客,跟了一下流程找到了关键的类–PhoneStatusBarPolicy。
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
PhoneStatusBarPolicy:定义了系统通知图标的设置策略,监听图标改变广播。
看下它的构造方法。

public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController) {mContext = context;mIconController = iconController;//省略...mSlotInputType = context.getString(com.android.internal.R.string.status_bar_input_type);mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);mSlotBluetooth = context.getString(com.android.internal.R.string.status_bar_bluetooth);mSlotTty = context.getString(com.android.internal.R.string.status_bar_tty);mSlotZen = context.getString(com.android.internal.R.string.status_bar_zen);mSlotVolume = context.getString(com.android.internal.R.string.status_bar_volume);mSlotAlarmClock = context.getString(com.android.internal.R.string.status_bar_alarm_clock);mSlotManagedProfile = context.getString(com.android.internal.R.string.status_bar_managed_profile);mSlotRotate = context.getString(com.android.internal.R.string.status_bar_rotate);mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset);mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver);mSlotLocation = context.getString(com.android.internal.R.string.status_bar_location);// listen for broadcastsIntentFilter filter = new IntentFilter();filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);filter.addAction(AudioManager.ACTION_HEADSET_PLUG);filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);// listen for user / profile change.try {ActivityManager.getService().registerUserSwitchObserver(mUserSwitchListener, TAG);} catch (RemoteException e) {// Ignore}// TTY statusupdateTTY();// bluetooth statusupdateBluetooth();// Alarm clockmIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);mIconController.setIconVisibility(mSlotAlarmClock, false);// zenmIconController.setIcon(mSlotZen, R.drawable.stat_sys_zen_important, null);mIconController.setIconVisibility(mSlotZen, false);// volumemIconController.setIcon(mSlotVolume, R.drawable.stat_sys_ringer_vibrate, null);mIconController.setIconVisibility(mSlotVolume, false);updateVolumeZen();// castmIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null);mIconController.setIconVisibility(mSlotCast, false);// hotspotmIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,mContext.getString(R.string.accessibility_status_bar_hotspot));mIconController.setIconVisibility(mSlotHotspot, mHotspot.isHotspotEnabled());// managed profilemIconController.setIcon(mSlotManagedProfile, R.drawable.stat_sys_managed_profile_status,mContext.getString(R.string.accessibility_managed_profile));mIconController.setIconVisibility(mSlotManagedProfile, mManagedProfileIconVisible);//省略...}

可以看到在构造方法中注册了广播接收器mIntentReceiver,用来接收各种状态的改变,去更改对应的图标。

private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {String action = intent.getAction();switch (action) {case AudioManager.RINGER_MODE_CHANGED_ACTION:case AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION:updateVolumeZen();break;case TelephonyIntents.ACTION_SIM_STATE_CHANGED:// Avoid rebroadcast because SysUI is direct boot aware.if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK,false)) {break;}updateSimState(intent);break;case TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED:updateTTY(intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE,TelecomManager.TTY_MODE_OFF));break;case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:case Intent.ACTION_MANAGED_PROFILE_REMOVED:updateManagedProfile();break;case AudioManager.ACTION_HEADSET_PLUG:updateHeadsetPlug(intent);break;case ACTION_INPUT_STATUS_CHANGED:updateInputType(intent);break;}}};

接下来看代码猜也能猜出来了。

// Alarm clockmIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);mIconController.setIconVisibility(mSlotAlarmClock, false);

很明显就是设置alarm图标的代码,第二行是控制显示还是隐藏。
ok,我们只需要模仿它来加上我们自己的图标就行了。

第一步声明Slot
其实就是个字符串而已。
frameworks/base/core/res/res/values/symbols.xml中加上声明

<java-symbol type="string" name="status_bar_input_type" />

在frameworks/base/core/res/res/values/config.xml的string-array name="config_statusBarIcons"中添加我们自己的slot。比如:

<item><xliff:g id="id">@string/status_bar_input_type</xliff:g></item>

然后继续添加

<string translatable="false" name="status_bar_input_type">input_type</string>

第二步
在PhoneStatusBarPolicy.java中添加图标。
先声明一个slot 和一个广播aciton

private final String mSlotInputType;
private final String ACTION_INPUT_STATUS_CHANGED = "android.intent.action.INPUT_STATUS_CHANGED";

在构造方法中初始化

 mSlotInputType = context.getString(com.android.internal.R.string.status_bar_input_type);
//...省略代码....filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);//添加的actionfilter.addAction(ACTION_INPUT_STATUS_CHANGED);mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);

第三步
在广播接收器中调用按键状态改变后的方法,去改变图标显示。

case ACTION_INPUT_STATUS_CHANGED:updateInputType(intent);break;

第四步
实现updateInputType方法

private int[] inputTypeArr = {R.drawable.y_button,    //yellowR.drawable.g_button     //green};private final void updateInputType(Intent intent) {final int input = intent.getIntExtra(mSlotInputType, 0);if (input >= inputTypeArr.length) return;if(input < 0){mIconController.setIconVisibility(mSlotInputType, false);return;}int iconId = inputTypeArr[input];mIconController.setIcon(mSlotInputType, iconId, null);mIconController.setIconVisibility(mSlotInputType, true);}

相信大家都能看懂,如果intent传过来的参数小于零就隐藏图标,大于零的话根据参数选择显示y图标还是g图标。别忘了把图标加到drawable下面。
packages/SystemUI/res/drawable-hdpi/g_button.png
packages/SystemUI/res/drawable-hdpi/y_button.png
图标可以从阿里巴巴图标库下载。
至此就已经添加完毕。
使用的话只需发广播就可以了

/*** update Input Status*/public void updateInputStatus(int inputState){Intent intent = new Intent(ACTION_INPUT_STATUS_CHANGED);intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);intent.putExtra(mContext.getString(R.string.status_bar_input_type), inputState);mContext.sendBroadcastAsUser(intent, UserHandle.ALL);}

我是放到PhoneWindowManager中的interceptKeyBeforeQueueing方法中调用的。因为这里可以拦截Keyevent事件,根据keycode,scancode判断是黄色还是绿色按键,然后再传入不同的inputState参数,来控制状态栏的图标。

说实话SystemUI代码还是挺复杂的,这里只是提供了添加图标的方法,并不涉及到StatusBar初始化流程,有兴趣的小伙伴可以自己尝试跟一下源码。

这篇关于Android状态栏右侧添加图标并控制其显示状态的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1092858

相关文章

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

浅析如何使用Swagger生成带权限控制的API文档

《浅析如何使用Swagger生成带权限控制的API文档》当涉及到权限控制时,如何生成既安全又详细的API文档就成了一个关键问题,所以这篇文章小编就来和大家好好聊聊如何用Swagger来生成带有... 目录准备工作配置 Swagger权限控制给 API 加上权限注解查看文档注意事项在咱们的开发工作里,API

linux进程D状态的解决思路分享

《linux进程D状态的解决思路分享》在Linux系统中,进程在内核模式下等待I/O完成时会进入不间断睡眠状态(D状态),这种状态下,进程无法通过普通方式被杀死,本文通过实验模拟了这种状态,并分析了如... 目录1. 问题描述2. 问题分析3. 实验模拟3.1 使用losetup创建一个卷作为pv的磁盘3.

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例

通过prometheus监控Tomcat运行状态的操作流程

《通过prometheus监控Tomcat运行状态的操作流程》文章介绍了如何安装和配置Tomcat,并使用Prometheus和TomcatExporter来监控Tomcat的运行状态,文章详细讲解了... 目录Tomcat安装配置以及prometheus监控Tomcat一. 安装并配置tomcat1、安装

Linux之进程状态&&进程优先级详解

《Linux之进程状态&&进程优先级详解》文章介绍了操作系统中进程的状态,包括运行状态、阻塞状态和挂起状态,并详细解释了Linux下进程的具体状态及其管理,此外,文章还讨论了进程的优先级、查看和修改进... 目录一、操作系统的进程状态1.1运行状态1.2阻塞状态1.3挂起二、linux下具体的状态三、进程的

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

Spring IOC控制反转的实现解析

《SpringIOC控制反转的实现解析》:本文主要介绍SpringIOC控制反转的实现,IOC是Spring的核心思想之一,它通过将对象的创建、依赖注入和生命周期管理交给容器来实现解耦,使开发者... 目录1. IOC的基本概念1.1 什么是IOC1.2 IOC与DI的关系2. IOC的设计目标3. IOC

如何设置vim永久显示行号

《如何设置vim永久显示行号》在Linux环境下,vim默认不显示行号,这在程序编译出错时定位错误语句非常不便,通过修改vim配置文件vimrc,可以在每次打开vim时永久显示行号... 目录设置vim永久显示行号1.临时显示行号2.永www.chinasem.cn久显示行号总结设置vim永久显示行号在li