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

相关文章

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

Linux系统性能检测命令详解

《Linux系统性能检测命令详解》本文介绍了Linux系统常用的监控命令(如top、vmstat、iostat、htop等)及其参数功能,涵盖进程状态、内存使用、磁盘I/O、系统负载等多维度资源监控,... 目录toppsuptimevmstatIOStatiotopslabtophtopdstatnmon

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class

IDEA Maven提示:未解析的依赖项的问题及解决

《IDEAMaven提示:未解析的依赖项的问题及解决》:本文主要介绍IDEAMaven提示:未解析的依赖项的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录IDEA Maven提示:未解析的依编程赖项例如总结IDEA Maven提示:未解析的依赖项例如

SpringBoot开发中十大常见陷阱深度解析与避坑指南

《SpringBoot开发中十大常见陷阱深度解析与避坑指南》在SpringBoot的开发过程中,即使是经验丰富的开发者也难免会遇到各种棘手的问题,本文将针对SpringBoot开发中十大常见的“坑... 目录引言一、配置总出错?是不是同时用了.properties和.yml?二、换个位置配置就失效?搞清楚加

linux重启命令有哪些? 7个实用的Linux系统重启命令汇总

《linux重启命令有哪些?7个实用的Linux系统重启命令汇总》Linux系统提供了多种重启命令,常用的包括shutdown-r、reboot、init6等,不同命令适用于不同场景,本文将详细... 在管理和维护 linux 服务器时,完成系统更新、故障排查或日常维护后,重启系统往往是必不可少的步骤。本文

Android DataBinding 与 MVVM使用详解

《AndroidDataBinding与MVVM使用详解》本文介绍AndroidDataBinding库,其通过绑定UI组件与数据源实现自动更新,支持双向绑定和逻辑运算,减少模板代码,结合MV... 目录一、DataBinding 核心概念二、配置与基础使用1. 启用 DataBinding 2. 基础布局

Python中对FFmpeg封装开发库FFmpy详解

《Python中对FFmpeg封装开发库FFmpy详解》:本文主要介绍Python中对FFmpeg封装开发库FFmpy,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、FFmpy简介与安装1.1 FFmpy概述1.2 安装方法二、FFmpy核心类与方法2.1 FF