小工具知识网

当前位置: 首页 > 行业知识 > Android 11 系统开发增加低电量弹窗提示 手机 平板 车载 TV 投影 通用

行业知识

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

2026-11-06 04:19:26 来源:互联网转载

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

SystemUIService ��启动PowerUI

()
public class SystemUIService extends Service {     @Override    public void onCreate() {        super.onCreate();        ((SystemUIApplication) getApplication()).startServicesIfNeeded();         // For debugging RescueParty        if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {            throw new RuntimeException();        }         if (Build.IS_DEBUGGABLE) {            // b/71353150 - looking for leaked binder proxies            BinderInternal.nSetBinderProxyCountEnabled(true);            BinderInternal.nSetBinderProxyCountWatermarks(1000,900);            BinderInternal.setBinderProxyCountCallback(                    new BinderInternal.BinderProxyLimitListener() {                        @Override                        public 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 启动时,启动SystemUIApplication的startServicesIfNeeded() 来启动SystemUI的各种服务  在SystemUIApplication中 启动PowerUI  config.xml 中config_systemUIServiceComponents          com.android.systemui.Dependency$DependencyCreator        com.android.systemui.util.NotificationChannels        com.android.systemui.statusbar.CommandQueue$CommandQueueStart        com.android.systemui.keyguard.KeyguardViewMediator        com.android.systemui.recents.Recents        com.android.systemui.volume.VolumeUI        com.android.systemui.stackpider.Divider        com.android.systemui.SystemBars        com.android.systemui.usb.StorageNotification        com.android.systemui.power.PowerUI        com.android.systemui.media.RingtonePlayer        com.android.systemui.keyboard.KeyboardUI        com.android.systemui.pip.PipUI        com.android.systemui.shortcut.ShortcutKeyDispatcher        @string/config_systemUIVendorServiceComponent        com.android.systemui.util.leak.GarbageMonitor$Service        com.android.systemui.LatencyTester        com.android.systemui.globalactions.GlobalActionsComponent        com.android.systemui.ScreenDecorations        com.android.systemui.biometrics.BiometricDialogImpl        com.android.systemui.SliceBroadcastRelayHandler        com.android.systemui.SizeCompatModeActivityController        com.android.systemui.statusbar.notification.InstantAppNotifier        com.android.systemui.theme.ThemeOverlayController          /**     * 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.     * 

This method must only be called from the main thread.

*/ public void startServicesIfNeeded() { String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources()); startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names); } SystemUIFactory的getSystemUIServiceComponents(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 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() { private ArraySet mOverlays = new ArraySet(); @Override public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) { mainHandler.post(new Runnable() { @Override public void run() { StatusBar statusBar = getComponent(StatusBar.class); if (statusBar != null) { plugin.setup(statusBar.getStatusBarWindow(), statusBar.getNavigationBarView(), new Callback(plugin)); } } }); } @Override public void onPluginDisconnected(OverlayPlugin plugin) { mainHandler.post(new Runnable() { @Override public 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; } @Override public void onHoldStatusBarOpenChange() { if (mPlugin.holdStatusBarOpen()) { mOverlays.add(mPlugin); } else { mOverlays.remove(mPlugin); } mainHandler.post(new Runnable() { @Override public 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) {@Overridepublic 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) {@Overridepublic 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) {@Overridepublic void onChange(boolean selfChange) {doUsbThermalEventListenerRegistration();}});initThermalEventListeners();mCommandQueue.addCallback(this);} @VisibleForTestingfinal 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 stateIntent intent = mContext.registerReceiver(null,new IntentFilter(Intent.ACTION_BATTERY_CHANGED));if (intent != null) {onReceive(mContext, intent);}}} @Overridepublic 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 batteryif (DEBUG) {Slog.d(TAG, "Bad Charger");}return;}// Show the correct version of low battery warning if neededif (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);}}}在PowerUI的start()方法中启动广播监听电量变化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的低电量提醒方法       @Override      public 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();        }     }        @Override      public 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    ... ...        低电量提醒        111        ... ...

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

在symbols文件中为全部string,int值注册,方便Framework层代码的引用。frameworks/base/core/res/res/values/symbols.xml          

上一篇:江苏浪潮服务器怎么样?

下一篇:E语言子程序结束详解,终止技巧轻松掌握!