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


    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 启动时,启动SystemUIApplicationstartServicesIfNeeded() 来启动SystemUI的各种服务
      在SystemUIApplication中 启动PowerUI
      config.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.
         * 

    This method must only be called from the main thread.

    */
    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 long ti = 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<>(); @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; }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190

    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的低电量提醒方法
           @Override
          public void showLowBatteryWarning(boolean playSound) {
              Slog.i(TAG,
                      "show low battery warning: level=" + mBatteryLevel
                             + " [" + mBucket + "] playSound=" + playSound);
              mPlaySound = playSound;
              mWarning = true;
              updateNotification();
          }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220

    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("低电量")
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    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.  See
           frameworks/base/core/res/MakeJavaSymbols.sed for how to easily generate
           this.
     
           Can be referenced in java code as: com.android.internal.R.<type>.<name>
           and in layout xml as: "@*android:/"
      -->
     
      <!-- add code begin-->
      <java-symbol type="string" name="lowbatteryWarning" />
      <java-symbol type="string" name="batteryLow111" />
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
  • 相关阅读:
    详解CentOS8更换yum源后出现同步仓库缓存失败的问题
    《TCP/IP网络编程》阅读笔记--多播与广播
    tvm交叉编译android opencl
    同样做软件测试,为什么有人月入3k-5k,有人能拿到17-20k?
    【Mysql】表的约束
    JVM高频面试题PDF版
    Go语言sync.Map
    (五)字符串——PHP
    设计模式:策略模式
    含文档+PPT+源码等]精品spring boot汽车销售管理系统[包运行成功]程序设计源码计算机毕设
  • 原文地址:https://blog.csdn.net/nq1737274479/article/details/136480011