Android 11 系统开发增加低电量弹窗提示 手机 平板 车载 TV 投影 通用

本文主要是介绍Android 11 系统开发增加低电量弹窗提示 手机 平板 车载 TV 投影 通用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1、PowerUI是系统中控制电量提示的模块,低电量提醒、低电量关机提醒、高温关机提醒、省电模式都在其中实现

SystemUIService 中启动PowerUI

public class SystemUIService extends Service {@Overridepublic void onCreate() {super.onCreate();((SystemUIApplication) getApplication()).startServicesIfNeeded();// For debugging RescuePartyif (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {throw new RuntimeException();}if (Build.IS_DEBUGGABLE) {// b/71353150 - looking for leaked binder proxiesBinderInternal.nSetBinderProxyCountEnabled(true);BinderInternal.nSetBinderProxyCountWatermarks(1000,900);BinderInternal.setBinderProxyCountCallback(new BinderInternal.BinderProxyLimitListener() {@Overridepublic void onLimitReached(int uid) {Slog.w(SystemUIApplication.TAG,"uid " + uid + " sent too many Binder proxies to uid "+ Process.myUid());}}, Dependency.get(Dependency.MAIN_HANDLER));}}SystemUIService 启动时,启动SystemUIApplicationstartServicesIfNeeded() 来启动SystemUI的各种服务在SystemUIApplication中 启动PowerUIconfig.xml 中config_systemUIServiceComponents<string-array name="config_systemUIServiceComponents" translatable="false"><item>com.android.systemui.Dependency$DependencyCreator</item><item>com.android.systemui.util.NotificationChannels</item><item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item><item>com.android.systemui.keyguard.KeyguardViewMediator</item><item>com.android.systemui.recents.Recents</item><item>com.android.systemui.volume.VolumeUI</item><item>com.android.systemui.stackdivider.Divider</item><item>com.android.systemui.SystemBars</item><item>com.android.systemui.usb.StorageNotification</item><item>com.android.systemui.power.PowerUI</item><item>com.android.systemui.media.RingtonePlayer</item><item>com.android.systemui.keyboard.KeyboardUI</item><item>com.android.systemui.pip.PipUI</item><item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item><item>@string/config_systemUIVendorServiceComponent</item><item>com.android.systemui.util.leak.GarbageMonitor$Service</item><item>com.android.systemui.LatencyTester</item><item>com.android.systemui.globalactions.GlobalActionsComponent</item><item>com.android.systemui.ScreenDecorations</item><item>com.android.systemui.biometrics.BiometricDialogImpl</item><item>com.android.systemui.SliceBroadcastRelayHandler</item><item>com.android.systemui.SizeCompatModeActivityController</item><item>com.android.systemui.statusbar.notification.InstantAppNotifier</item><item>com.android.systemui.theme.ThemeOverlayController</item></string-array>/*** Makes sure that all the SystemUI services are running. If they are already running, this is a* no-op. This is needed to conditinally start all the services, as we only need to have it in* the main process.* <p>This method must only be called from the main thread.</p>*/public void startServicesIfNeeded() {String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);}SystemUIFactorygetSystemUIServiceComponents(Resources resources)public String[] getSystemUIServiceComponents(Resources resources) {return resources.getStringArray(R.array.config_systemUIServiceComponents);}private void startServicesIfNeeded(String[] services) {if (mServicesStarted) {return;}mServices = new SystemUI[services.length];if (!mBootCompleted) {// check to see if maybe it was already completed long before we began// see ActivityManagerService.finishBooting()if ("1".equals(SystemProperties.get("sys.boot_completed"))) {mBootCompleted = true;if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");}}Log.v(TAG, "Starting SystemUI services for user " +Process.myUserHandle().getIdentifier() + ".");TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",Trace.TRACE_TAG_APP);log.traceBegin("StartServices");final int N = services.length;for (int i = 0; i < N; i++) {String clsName = services[i];if (DEBUG) Log.d(TAG, "loading: " + clsName);log.traceBegin("StartServices" + clsName);long ti = System.currentTimeMillis();Class cls;try {cls = Class.forName(clsName);Object o = cls.newInstance();if (o instanceof SystemUI.Injector) {o = ((SystemUI.Injector) o).apply(this);}mServices[i] = (SystemUI) o;} catch(ClassNotFoundException ex){throw new RuntimeException(ex);} catch (IllegalAccessException ex) {throw new RuntimeException(ex);} catch (InstantiationException ex) {throw new RuntimeException(ex);}mServices[i].mContext = this;mServices[i].mComponents = mComponents;if (DEBUG) Log.d(TAG, "running: " + mServices[i]);mServices[i].start();log.traceEnd();// Warn if initialization of component takes too longti = System.currentTimeMillis() - ti;if (ti > 1000) {Log.w(TAG, "Initialization of " + cls.getName() + " took " + ti + " ms");}if (mBootCompleted) {mServices[i].onBootCompleted();}}Dependency.get(InitController.class).executePostInitTasks();log.traceEnd();final Handler mainHandler = new Handler(Looper.getMainLooper());Dependency.get(PluginManager.class).addPluginListener(new PluginListener<OverlayPlugin>() {private ArraySet<OverlayPlugin> mOverlays = new ArraySet<>();@Overridepublic void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {mainHandler.post(new Runnable() {@Overridepublic void run() {StatusBar statusBar = getComponent(StatusBar.class);if (statusBar != null) {plugin.setup(statusBar.getStatusBarWindow(),statusBar.getNavigationBarView(), new Callback(plugin));}}});}@Overridepublic void onPluginDisconnected(OverlayPlugin plugin) {mainHandler.post(new Runnable() {@Overridepublic void run() {mOverlays.remove(plugin);Dependency.get(StatusBarWindowController.class).setForcePluginOpen(mOverlays.size() != 0);}});}class Callback implements OverlayPlugin.Callback {private final OverlayPlugin mPlugin;Callback(OverlayPlugin plugin) {mPlugin = plugin;}@Overridepublic void onHoldStatusBarOpenChange() {if (mPlugin.holdStatusBarOpen()) {mOverlays.add(mPlugin);} else {mOverlays.remove(mPlugin);}mainHandler.post(new Runnable() {@Overridepublic void run() {Dependency.get(StatusBarWindowController.class).setStateListener(b -> mOverlays.forEach(o -> o.setCollapseDesired(b)));Dependency.get(StatusBarWindowController.class).setForcePluginOpen(mOverlays.size() != 0);}});}}}, OverlayPlugin.class, true /* Allow multiple plugins */);mServicesStarted = true;}

2、PowerUI 电量的分析

public void start() {
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
mWarnings = Dependency.get(WarningsUI.class);
mEnhancedEstimates = Dependency.get(EnhancedEstimates.class);
mLastConfiguration.setTo(mContext.getResources().getConfiguration());ContentObserver obs = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
updateBatteryWarningLevels();
}
};
final ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Global.getUriFor(
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
false, obs, UserHandle.USER_ALL);
updateBatteryWarningLevels();
mReceiver.init();// Check to see if we need to let the user know that the phone previously shut down due
// to the temperature being too high.
showWarnOnThermalShutdown();// Register an observer to configure mEnableSkinTemperatureWarning and perform the
// registration of skin thermal event listener upon Settings change.
resolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.SHOW_TEMPERATURE_WARNING),
false /*notifyForDescendants*/,
new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
doSkinThermalEventListenerRegistration();
}
});
// Register an observer to configure mEnableUsbTemperatureAlarm and perform the
// registration of usb thermal event listener upon Settings change.
resolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.SHOW_USB_TEMPERATURE_ALARM),
false /*notifyForDescendants*/,
new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
doUsbThermalEventListenerRegistration();
}
});
initThermalEventListeners();
mCommandQueue.addCallback(this);
}@VisibleForTesting
final class Receiver extends BroadcastReceiver {private boolean mHasReceivedBattery = false;public void init() {
// Register for Intent broadcasts for...
IntentFilter filter = new IntentFilter();
filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_USER_SWITCHED);
mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler);
// Force get initial values. Relying on Sticky behavior until API for getting info.
if (!mHasReceivedBattery) {
// Get initial state
Intent intent = mContext.registerReceiver(
null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED)
);
if (intent != null) {
onReceive(mContext, intent);
}
}
}@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) {
ThreadUtils.postOnBackgroundThread(() -> {
if (mPowerManager.isPowerSaveMode()) {
mWarnings.dismissLowBatteryWarning();
}
});
} else if (Intent.ACTION_BATTERY_CHANGED.equals(action)) {
mHasReceivedBattery = true;
final int oldBatteryLevel = mBatteryLevel;
mBatteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 100);
final int oldBatteryStatus = mBatteryStatus;
mBatteryStatus = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
final int oldPlugType = mPlugType;
mPlugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 1);
final int oldInvalidCharger = mInvalidCharger;
mInvalidCharger = intent.getIntExtra(BatteryManager.EXTRA_INVALID_CHARGER, 0);
mLastBatteryStateSnapshot = mCurrentBatteryStateSnapshot;final boolean plugged = mPlugType != 0;
final boolean oldPlugged = oldPlugType != 0;int oldBucket = findBatteryLevelBucket(oldBatteryLevel);
int bucket = findBatteryLevelBucket(mBatteryLevel);if (DEBUG) {
Slog.d(TAG, "buckets   ....." + mLowBatteryAlertCloseLevel
+ " .. " + mLowBatteryReminderLevels[0]
+ " .. " + mLowBatteryReminderLevels[1]);
Slog.d(TAG, "level          " + oldBatteryLevel + " --> " + mBatteryLevel);
Slog.d(TAG, "status         " + oldBatteryStatus + " --> " + mBatteryStatus);
Slog.d(TAG, "plugType       " + oldPlugType + " --> " + mPlugType);
Slog.d(TAG, "invalidCharger " + oldInvalidCharger + " --> " + mInvalidCharger);
Slog.d(TAG, "bucket         " + oldBucket + " --> " + bucket);
Slog.d(TAG, "plugged        " + oldPlugged + " --> " + plugged);
}mWarnings.update(mBatteryLevel, bucket, mScreenOffTime);
if (oldInvalidCharger == 0 && mInvalidCharger != 0) {
Slog.d(TAG, "showing invalid charger warning");
mWarnings.showInvalidChargerWarning();
return;
} else if (oldInvalidCharger != 0 && mInvalidCharger == 0) {
mWarnings.dismissInvalidChargerWarning();
} else if (mWarnings.isInvalidChargerWarningShowing()) {
// if invalid charger is showing, don't show low battery
if (DEBUG) {
Slog.d(TAG, "Bad Charger");
}
return;
}
// Show the correct version of low battery warning if needed
if (mLastShowWarningTask != null) {
mLastShowWarningTask.cancel(true);
if (DEBUG) {
Slog.d(TAG, "cancelled task");
}
}
//
mLastShowWarningTask = ThreadUtils.postOnBackgroundThread(() -> {
maybeShowBatteryWarningV2(
plugged, bucket);
});
} else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
mScreenOffTime = SystemClock.elapsedRealtime();
} else if (Intent.ACTION_SCREEN_ON.equals(action)) {
mScreenOffTime = -1;
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
mWarnings.userSwitched();
} else {
Slog.w(TAG, "unknown intent: " + intent);
}
}
}PowerUIstart()方法中启动广播监听电量变化
mLastShowWarningTask = ThreadUtils.postOnBackgroundThread(() -> {
maybeShowBatteryWarningV2(
plugged, bucket);
});
来判断是否开启低电量警告
protected void maybeShowBatteryWarningV2(boolean plugged, int bucket) {
final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled();
final boolean isPowerSaverMode = mPowerManager.isPowerSaveMode();
// Stick current battery state into an immutable container to determine if we should show
// a warning.
if (DEBUG) {
Slog.d(TAG, "evaluating which notification to show");
}
if (hybridEnabled) {
if (DEBUG) {
Slog.d(TAG, "using hybrid");
}
Estimate estimate = refreshEstimateIfNeeded();
mCurrentBatteryStateSnapshot = new BatteryStateSnapshot(mBatteryLevel, isPowerSaverMode,
plugged, bucket, mBatteryStatus, mLowBatteryReminderLevels[1],
mLowBatteryReminderLevels[0], estimate.getEstimateMillis(),
estimate.getAverageDischargeTime(),
mEnhancedEstimates.getSevereWarningThreshold(),
mEnhancedEstimates.getLowWarningThreshold(), estimate.isBasedOnUsage(),
mEnhancedEstimates.getLowWarningEnabled());
} else {
if (DEBUG) {
Slog.d(TAG, "using standard");
}
mCurrentBatteryStateSnapshot = new BatteryStateSnapshot(mBatteryLevel, isPowerSaverMode,
plugged, bucket, mBatteryStatus, mLowBatteryReminderLevels[1],
mLowBatteryReminderLevels[0]);
}
mWarnings.updateSnapshot(mCurrentBatteryStateSnapshot);
if (mCurrentBatteryStateSnapshot.isHybrid()) {
maybeShowHybridWarning(mCurrentBatteryStateSnapshot, mLastBatteryStateSnapshot);
} else {
//低电量警告
maybeShowBatteryWarning(mCurrentBatteryStateSnapshot, mLastBatteryStateSnapshot);
}
protected void maybeShowBatteryWarning(BatteryStateSnapshot currentSnapshot,BatteryStateSnapshot lastSnapshot) {final boolean playSound = currentSnapshot.getBucket() != lastSnapshot.getBucket()|| lastSnapshot.getPlugged();if (shouldShowLowBatteryWarning(currentSnapshot, lastSnapshot)) {mWarnings.showLowBatteryWarning(playSound);//低电量警告} else if (shouldDismissLowBatteryWarning(currentSnapshot, lastSnapshot)) {mWarnings.dismissLowBatteryWarning();//去掉低电量警告} else {mWarnings.updateLowBatteryWarning();}}PowerNotificationWarnings.java的低电量提醒方法@Overridepublic void showLowBatteryWarning(boolean playSound) {Slog.i(TAG,"show low battery warning: level=" + mBatteryLevel+ " [" + mBucket + "] playSound=" + playSound);mPlaySound = playSound;mWarning = true;updateNotification();}
}

3、增加低电量的弹窗 PowerNotificationWarnings.java的showLowBatteryWarning()方法

import android.app.AlertDialog;import android.view.WindowManager;import android.content.DialogInterface;private AlertDialog mbatteryLowDialog = null;// 自定义电池温度Dialog弹窗private void batterylowDialog(String lowbattery) {mbatteryLowDialog = new AlertDialog(mContext);AlertDialog.Builder builder = new AlertDialog.Builder(mContext);builder.setTitle(mContext.getResources().getString(com.android.internal.R.string.lowbatteryWarning));builder.setCancelable(false);builder.setMessage(lowbattery);builder.setIconAttribute(android.R.attr.alertDialogIcon);builder.setPositiveButton(com.android.internal.R.string.batteryLow111,new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialog, int id) {dialog.cancel();mbatteryLowDialog = null;}});mbatteryLowDialog = builder.create();mbatteryLowDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);if (mbatteryLowDialog != null&& !mbatteryLowDialog.isShowing()) {mbatteryLowDialog.show();}}@Overridepublic void showLowBatteryWarning(boolean playSound) {Slog.i(TAG,"show low battery warning: level=" + mBatteryLevel+ " [" + mBucket + "] playSound=" + playSound);mPlaySound = playSound;mWarning = true;updateNotification();+ batterylowDialog("低电量")}

4、增加低电量提醒的xml资源

主要修改

frameworks/base/core/res/res/values/string.xml
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">... ...<!-- Shutdown if the battery temperature exceeds (this value * 0.1) Celsius. --><string name="lowbatteryWarning">低电量提醒</integer><!-- add code begin--><string name="batteryLow111">111</integer><!-- add code end-->... ...
</resources>

5、在symbols 文件中添加对应java-symbol方便Framework代码引用code

在symbols文件中为全部string,int值注册,方便Framework层代码的引用。
frameworks/base/core/res/res/values/symbols.xml<?xml version="1.0" encoding="utf-8"?>
<resources><!-- Private symbols that we need to reference from framework code.  Seeframeworks/base/core/res/MakeJavaSymbols.sed for how to easily generatethis.Can be referenced in java code as: com.android.internal.R.<type>.<name>and in layout xml as: "@*android:<type>/<name>"--><!-- add code begin--><java-symbol type="string" name="lowbatteryWarning" /><java-symbol type="string" name="batteryLow111" />

这篇关于Android 11 系统开发增加低电量弹窗提示 手机 平板 车载 TV 投影 通用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

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

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

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

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

在不同系统间迁移Python程序的方法与教程

《在不同系统间迁移Python程序的方法与教程》本文介绍了几种将Windows上编写的Python程序迁移到Linux服务器上的方法,包括使用虚拟环境和依赖冻结、容器化技术(如Docker)、使用An... 目录使用虚拟环境和依赖冻结1. 创建虚拟环境2. 冻结依赖使用容器化技术(如 docker)1. 创

CentOS系统Maven安装教程分享

《CentOS系统Maven安装教程分享》本文介绍了如何在CentOS系统中安装Maven,并提供了一个简单的实际应用案例,安装Maven需要先安装Java和设置环境变量,Maven可以自动管理项目的... 目录准备工作下载并安装Maven常见问题及解决方法实际应用案例总结Maven是一个流行的项目管理工具

基于Python开发PPTX压缩工具

《基于Python开发PPTX压缩工具》在日常办公中,PPT文件往往因为图片过大而导致文件体积过大,不便于传输和存储,所以本文将使用Python开发一个PPTX压缩工具,需要的可以了解下... 目录引言全部代码环境准备代码结构代码实现运行结果引言在日常办公中,PPT文件往往因为图片过大而导致文件体积过大,

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

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

使用DeepSeek API 结合VSCode提升开发效率

《使用DeepSeekAPI结合VSCode提升开发效率》:本文主要介绍DeepSeekAPI与VisualStudioCode(VSCode)结合使用,以提升软件开发效率,具有一定的参考价值... 目录引言准备工作安装必要的 VSCode 扩展配置 DeepSeek API1. 创建 API 请求文件2.

C#实现系统信息监控与获取功能

《C#实现系统信息监控与获取功能》在C#开发的众多应用场景中,获取系统信息以及监控用户操作有着广泛的用途,比如在系统性能优化工具中,需要实时读取CPU、GPU资源信息,本文将详细介绍如何使用C#来实现... 目录前言一、C# 监控键盘1. 原理与实现思路2. 代码实现二、读取 CPU、GPU 资源信息1.

在C#中获取端口号与系统信息的高效实践

《在C#中获取端口号与系统信息的高效实践》在现代软件开发中,尤其是系统管理、运维、监控和性能优化等场景中,了解计算机硬件和网络的状态至关重要,C#作为一种广泛应用的编程语言,提供了丰富的API来帮助开... 目录引言1. 获取端口号信息1.1 获取活动的 TCP 和 UDP 连接说明:应用场景:2. 获取硬

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma