Android 电量百分比的显示 您所在的位置:网站首页 sketch安卓状态栏控件在哪 Android 电量百分比的显示

Android 电量百分比的显示

2024-07-10 15:56| 来源: 网络整理| 查看: 265

Android 电量的显示在statusBar里,属于SystemUI,源码在 :

frameworks\base\packages\SystemUI\src\com\android\systemui\BatteryMeterView.java

构造方法如下:

在batteryMeterView的构造方法中,new 了 一个ImageView,该VIew就是电池图标的View

通过setImageDrawable设置图片为mDrawable, mDrawable是通过代码绘制而成的

public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); BroadcastDispatcher broadcastDispatcher = Dependency.get(BroadcastDispatcher.class); setOrientation(LinearLayout.HORIZONTAL); setGravity(Gravity.CENTER_VERTICAL | Gravity.START); TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView, defStyle, 0); final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor, context.getColor(R.color.meter_background_color)); mPercentageStyleId = atts.getResourceId(R.styleable.BatteryMeterView_textAppearance, 0); mDrawable = new ThemedBatteryDrawable(context, frameColor); atts.recycle(); mSettingObserver = new SettingObserver(new Handler(context.getMainLooper())); mShowPercentAvailable = context.getResources().getBoolean( com.android.internal.R.bool.config_battery_percentage_setting_available); addOnAttachStateChangeListener( new DisableStateTracker(DISABLE_NONE, DISABLE2_SYSTEM_ICONS, Dependency.get(CommandQueue.class))); setupLayoutTransition(); mSlotBattery = context.getString( com.android.internal.R.string.status_bar_battery); mBatteryIconView = new ImageView(context); mBatteryIconView.setImageDrawable(mDrawable); final MarginLayoutParams mlp = new MarginLayoutParams( getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_width), getResources().getDimensionPixelSize(R.dimen.status_bar_battery_icon_height)); mlp.setMargins(0, 0, 0, getResources().getDimensionPixelOffset(R.dimen.battery_margin_bottom)); addView(mBatteryIconView, mlp); updateShowPercent(); mDualToneHandler = new DualToneHandler(context); // Init to not dark at all. onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT); mUserTracker = new CurrentUserTracker(broadcastDispatcher) { @Override public void onUserSwitched(int newUserId) { mUser = newUserId; getContext().getContentResolver().unregisterContentObserver(mSettingObserver); getContext().getContentResolver().registerContentObserver( Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, newUserId); updateShowPercent(); } }; setClipChildren(false); setClipToPadding(false); Dependency.get(ConfigurationController.class).observe(viewAttachLifecycle(this), this); }

当电量发生改变的时候 调用onBatteryLevelChanged

@Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { mDrawable.setCharging(pluggedIn); mDrawable.setBatteryLevel(level); mCharging = pluggedIn; mLevel = level; updatePercentText(); }

private void updatePercentText() { if (mBatteryController == null) { return; } if (mBatteryPercentView != null) { if (mShowPercentMode == MODE_ESTIMATE && !mCharging) { mBatteryController.getEstimatedTimeRemainingString((String estimate) -> { if (estimate != null) { mBatteryPercentView.setText(estimate); setContentDescription(getContext().getString( R.string.accessibility_battery_level_with_estimate, mLevel, estimate)); } else { setPercentTextAtCurrentLevel(); } }); } else { setPercentTextAtCurrentLevel(); } } else { setContentDescription( getContext().getString(mCharging ? R.string.accessibility_battery_level_charging : R.string.accessibility_battery_level, mLevel)); } } private void setPercentTextAtCurrentLevel() { mBatteryPercentView.setText( NumberFormat.getPercentInstance().format(mLevel / 100f)); setContentDescription( getContext().getString(mCharging ? R.string.accessibility_battery_level_charging : R.string.accessibility_battery_level, mLevel)); }

有线充电和无线充电的判断

 mPowerPluggedInWired = status.isPluggedInWired() && isChargingOrFull;

@VisibleForTesting String computePowerIndication() { if (mPowerCharged) { return mContext.getResources().getString(R.string.keyguard_charged); } final boolean hasChargingTime = mChargingTimeRemaining > 0; int chargingId; if (mPowerPluggedInWired) { switch (mChargingSpeed) { case BatteryStatus.CHARGING_FAST: chargingId = hasChargingTime ? R.string.keyguard_indication_charging_time_fast : R.string.keyguard_plugged_in_charging_fast; break; case BatteryStatus.CHARGING_SLOWLY: chargingId = hasChargingTime ? R.string.keyguard_indication_charging_time_slowly : R.string.keyguard_plugged_in_charging_slowly; break; default: chargingId = hasChargingTime ? R.string.keyguard_indication_charging_time : R.string.keyguard_plugged_in; break; } } else { chargingId = hasChargingTime ? R.string.keyguard_indication_charging_time_wireless : R.string.keyguard_plugged_in_wireless; } String percentage = NumberFormat.getPercentInstance() .format(mBatteryLevel / 100f); if (hasChargingTime) { // We now have battery percentage in these strings and it's expected that all // locales will also have it in the future. For now, we still have to support the old // format until all languages get the new translations. String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes( mContext, mChargingTimeRemaining); try { return mContext.getResources().getString(chargingId, chargingTimeFormatted, percentage); } catch (IllegalFormatConversionException e) { return mContext.getResources().getString(chargingId, chargingTimeFormatted); } } else { // Same as above try { return mContext.getResources().getString(chargingId, percentage); } catch (IllegalFormatConversionException e) { return mContext.getResources().getString(chargingId); } } }

frameworks/base/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java

public BatteryStatus(Intent batteryChangedIntent) { status = batteryChangedIntent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN); plugged = batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0); level = batteryChangedIntent.getIntExtra(EXTRA_LEVEL, 0); health = batteryChangedIntent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN); final int maxChargingMicroAmp = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_CURRENT, -1); int maxChargingMicroVolt = batteryChangedIntent.getIntExtra(EXTRA_MAX_CHARGING_VOLTAGE, -1); if (maxChargingMicroVolt 0) { // Calculating muW = muA * muV / (10^6 mu^2 / mu); splitting up the divisor // to maintain precision equally on both factors. maxChargingWattage = (maxChargingMicroAmp / 1000) * (maxChargingMicroVolt / 1000); } else { maxChargingWattage = -1; } }

判断是否是有线充电 

public boolean isPluggedInWired() { return plugged == BatteryManager.BATTERY_PLUGGED_AC || plugged == BatteryManager.BATTERY_PLUGGED_USB; }

判断是否在充电 

/** * Determine whether the device is plugged in (USB, power, or wireless). * * @return true if the device is plugged in. */ public boolean isPluggedIn() { return plugged == BatteryManager.BATTERY_PLUGGED_AC || plugged == BatteryManager.BATTERY_PLUGGED_USB || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS; }

 充电速度的判断

/** * Return current chargin speed is fast, slow or normal. * * @return the charing speed */ public final int getChargingSpeed(Context context) { final int slowThreshold = context.getResources().getInteger( R.integer.config_chargingSlowlyThreshold); final int fastThreshold = context.getResources().getInteger( R.integer.config_chargingFastThreshold); return maxChargingWattage fastThreshold ? CHARGING_FAST : CHARGING_REGULAR; }

frameworks\base\packages\SettingsLib\res\values\config.xml

5000000 7500000 @Override public void onRefreshBatteryInfo(BatteryStatus status) { boolean isChargingOrFull = status.status == BatteryManager.BATTERY_STATUS_CHARGING || status.status == BatteryManager.BATTERY_STATUS_FULL; boolean wasPluggedIn = mPowerPluggedIn; mPowerPluggedInWired = status.isPluggedInWired() && isChargingOrFull; mPowerPluggedIn = status.isPluggedIn() && isChargingOrFull; mPowerCharged = status.isCharged(); mChargingWattage = status.maxChargingWattage; mChargingSpeed = status.getChargingSpeed(mContext); mBatteryLevel = status.level; try { mChargingTimeRemaining = mPowerPluggedIn ? mBatteryInfo.computeChargeTimeRemaining() : -1; } catch (RemoteException e) { Log.e(TAG, "Error calling IBatteryStats: ", e); mChargingTimeRemaining = -1; } updateIndication(!wasPluggedIn && mPowerPluggedInWired); if (mDozing) { if (!wasPluggedIn && mPowerPluggedIn) { showTransientIndication(computePowerIndication()); hideTransientIndicationDelayed(HIDE_DELAY_MS); } else if (wasPluggedIn && !mPowerPluggedIn) { hideTransientIndication(); } } }

frameworks\base\packages\SystemUI\src\com\android\systemui\statusbar\policy\BatteryControllerImpl.java

该控制器监控系统广播的电池电量变化事件。

注册广播接收器

private void registerReceiver() { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); filter.addAction(ACTION_LEVEL_TEST); mBroadcastDispatcher.registerReceiver(this, filter); } @Override public void init() { registerReceiver(); if (!mHasReceivedBattery) { // Get initial state. Relying on Sticky behavior until API for getting info. Intent intent = mContext.registerReceiver( null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED) ); if (intent != null && !mHasReceivedBattery) { onReceive(mContext, intent); } } updatePowerSave(); updateEstimate(); }

 在回调的时候更新电量

@Override public void addCallback(BatteryController.BatteryStateChangeCallback cb) { synchronized (mChangeCallbacks) { mChangeCallbacks.add(cb); } if (!mHasReceivedBattery) return; cb.onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); cb.onPowerSaveChanged(mPowerSave); } @Override public void removeCallback(BatteryController.BatteryStateChangeCallback cb) { synchronized (mChangeCallbacks) { mChangeCallbacks.remove(cb); } } @Override public void onReceive(final Context context, Intent intent) { final String action = intent.getAction(); if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { if (mTestmode && !intent.getBooleanExtra("testmode", false)) return; mHasReceivedBattery = true; mLevel = (int)(100f * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0) / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100)); mPluggedIn = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0; final int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN); mCharged = status == BatteryManager.BATTERY_STATUS_FULL; mCharging = mCharged || status == BatteryManager.BATTERY_STATUS_CHARGING; fireBatteryLevelChanged(); } else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)) { updatePowerSave(); } else if (action.equals(ACTION_LEVEL_TEST)) { mTestmode = true; mMainHandler.post(new Runnable() { int curLevel = 0; int incr = 1; int saveLevel = mLevel; boolean savePlugged = mPluggedIn; Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED); @Override public void run() { if (curLevel < 0) { mTestmode = false; dummy.putExtra("level", saveLevel); dummy.putExtra("plugged", savePlugged); dummy.putExtra("testmode", false); } else { dummy.putExtra("level", curLevel); dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC : 0); dummy.putExtra("testmode", true); } context.sendBroadcast(dummy); if (!mTestmode) return; curLevel += incr; if (curLevel == 100) { incr *= -1; } mMainHandler.postDelayed(this, 200); } }); } }

 调用回调更新电量

protected void fireBatteryLevelChanged() { synchronized (mChangeCallbacks) { final int N = mChangeCallbacks.size(); for (int i = 0; i < N; i++) { mChangeCallbacks.get(i).onBatteryLevelChanged(mLevel, mPluggedIn, mCharging); } } }

 BatteryMeterView在onAttachedToWindow方法中addCallback

@Override public void onAttachedToWindow() { super.onAttachedToWindow(); mBatteryController = Dependency.get(BatteryController.class); mBatteryController.addCallback(this); mUser = ActivityManager.getCurrentUser(); getContext().getContentResolver().registerContentObserver( Settings.System.getUriFor(SHOW_BATTERY_PERCENT), false, mSettingObserver, mUser); getContext().getContentResolver().registerContentObserver( Settings.Global.getUriFor(Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME), false, mSettingObserver); updateShowPercent(); subscribeForTunerUpdates(); mUserTracker.startTracking(); } @Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { mDrawable.setCharging(pluggedIn); mDrawable.setBatteryLevel(level); mCharging = pluggedIn; mLevel = level; updatePercentText(); }

 省电模式:

frameworks/base/core/java/android/os/PowerManager.java

/** * Returns true if the device is currently in power save mode. When in this mode, * applications should reduce their functionality in order to conserve battery as * much as possible. You can monitor for changes to this state with * {@link #ACTION_POWER_SAVE_MODE_CHANGED}. * * @return Returns true if currently in low power mode, else false. */ public boolean isPowerSaveMode() { return mPowerSaveModeCache.query(null); }

frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java

@Override // Binder call public boolean isPowerSaveMode() { final long ident = Binder.clearCallingIdentity(); try { return mBatterySaverController.isEnabled(); } finally { Binder.restoreCallingIdentity(ident); } }

frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy

三种省电模式

static final int POLICY_LEVEL_OFF = 0; static final int POLICY_LEVEL_ADAPTIVE = 1; static final int POLICY_LEVEL_FULL = 2;

frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java 

@Override // Binder call public boolean setPowerSaveModeEnabled(boolean enabled) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.POWER_SAVER) != PackageManager.PERMISSION_GRANTED) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DEVICE_POWER, null); } final long ident = Binder.clearCallingIdentity(); try { return setLowPowerModeInternal(enabled); } finally { Binder.restoreCallingIdentity(ident); } } 充电状态下,不允许打开/关闭省电模式 private boolean setLowPowerModeInternal(boolean enabled) { synchronized (mLock) { if (DEBUG) { Slog.d(TAG, "setLowPowerModeInternal " + enabled + " mIsPowered=" + mIsPowered); } if (mIsPowered) { return false; } mBatterySaverStateMachine.setBatterySaverEnabledManually(enabled); return true; } }

打开省电模式时,通过 BatterySaverStateMachine.setBatterySaverEnabledManually() 方法,把指令传给状态机

frameworks/base/services/core/java/com/android/server/power/batterysaver/BatterySaverStateMachine.java

/** * {@link com.android.server.power.PowerManagerService} calls it when * {@link android.os.PowerManager#setPowerSaveModeEnabled} is called. * * Note this could? be called before {@link #onBootCompleted} too. */ public void setBatterySaverEnabledManually(boolean enabled) { if (DEBUG) { Slog.d(TAG, "setBatterySaverEnabledManually: enabled=" + enabled); } synchronized (mLock) { updateStateLocked(true, enabled); // TODO: maybe turn off adaptive if it's on and advertiseIsEnabled is true and // enabled is false } }

状态机通过 updateStateLocked() 更新内部状态,然后根据状态执行相应的操作。 注意,这里的第一个参数表示是否是用户手动打开省电模式,值为 true,第二个参数表示是否打开省电模式

@GuardedBy("mLock") private void updateStateLocked(boolean manual, boolean enable) { if (!manual && !(mBootCompleted && mSettingsLoaded && mBatteryStatusSet)) { return; // Not fully initialized yet. } switch (mState) { case STATE_OFF: { if (!mIsPowered) { if (manual) { if (!enable) { Slog.e(TAG, "Tried to disable BS when it's already OFF"); return; } enableBatterySaverLocked(/*enable*/ true, /*manual*/ true, BatterySaverController.REASON_MANUAL_ON); hideStickyDisabledNotification(); mState = STATE_MANUAL_ON; } else if (isAutomaticModeActiveLocked() && isInAutomaticLowZoneLocked()) { enableBatterySaverLocked(/*enable*/ true, /*manual*/ false, BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON); hideStickyDisabledNotification(); mState = STATE_AUTOMATIC_ON; } else if (isDynamicModeActiveLocked() && isInDynamicLowZoneLocked()) { enableBatterySaverLocked(/*enable*/ true, /*manual*/ false, BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON); hideStickyDisabledNotification(); mState = STATE_AUTOMATIC_ON; } } break; } case STATE_MANUAL_ON: { if (manual) { if (enable) { Slog.e(TAG, "Tried to enable BS when it's already MANUAL_ON"); return; } enableBatterySaverLocked(/*enable*/ false, /*manual*/ true, BatterySaverController.REASON_MANUAL_OFF); mState = STATE_OFF; } else if (mIsPowered) { enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, BatterySaverController.REASON_PLUGGED_IN); if (mSettingBatterySaverEnabledSticky && !mBatterySaverStickyBehaviourDisabled) { mState = STATE_PENDING_STICKY_ON; } else { mState = STATE_OFF; } } break; } case STATE_AUTOMATIC_ON: { if (mIsPowered) { enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, BatterySaverController.REASON_PLUGGED_IN); mState = STATE_OFF; } else if (manual) { if (enable) { Slog.e(TAG, "Tried to enable BS when it's already AUTO_ON"); return; } enableBatterySaverLocked(/*enable*/ false, /*manual*/ true, BatterySaverController.REASON_MANUAL_OFF); // When battery saver is disabled manually (while battery saver is enabled) // when the battery level is low, we "snooze" BS -- i.e. disable auto battery // saver. // We resume auto-BS once the battery level is not low, or the device is // plugged in. mState = STATE_OFF_AUTOMATIC_SNOOZED; } else if (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked()) { enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF); mState = STATE_OFF; } else if (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked()) { enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF); mState = STATE_OFF; } else if (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked()) { enableBatterySaverLocked(/*enable*/ false, /*manual*/ false, BatterySaverController.REASON_SETTING_CHANGED); mState = STATE_OFF; } break; } case STATE_OFF_AUTOMATIC_SNOOZED: { if (manual) { if (!enable) { Slog.e(TAG, "Tried to disable BS when it's already AUTO_SNOOZED"); return; } enableBatterySaverLocked(/*enable*/ true, /*manual*/ true, BatterySaverController.REASON_MANUAL_ON); mState = STATE_MANUAL_ON; } else if (mIsPowered // Plugging in resets snooze. || (isAutomaticModeActiveLocked() && !isInAutomaticLowZoneLocked()) || (isDynamicModeActiveLocked() && !isInDynamicLowZoneLocked()) || (!isAutomaticModeActiveLocked() && !isDynamicModeActiveLocked())) { mState = STATE_OFF; } break; } case STATE_PENDING_STICKY_ON: { if (manual) { // This shouldn't be possible. We'll only be in this state when the device is // plugged in, so the user shouldn't be able to manually change state. Slog.e(TAG, "Tried to manually change BS state from PENDING_STICKY_ON"); return; } final boolean shouldTurnOffSticky = mSettingBatterySaverStickyAutoDisableEnabled && mBatteryLevel >= mSettingBatterySaverStickyAutoDisableThreshold; final boolean isStickyDisabled = mBatterySaverStickyBehaviourDisabled || !mSettingBatterySaverEnabledSticky; if (isStickyDisabled || shouldTurnOffSticky) { mState = STATE_OFF; setStickyActive(false); triggerStickyDisabledNotification(); } else if (!mIsPowered) { // Re-enable BS. enableBatterySaverLocked(/*enable*/ true, /*manual*/ true, BatterySaverController.REASON_STICKY_RESTORE); mState = STATE_MANUAL_ON; } break; } default: Slog.wtf(TAG, "Unknown state: " + mState); break; } }

状态机里的默认状态是 STATE_OFF,表示省电模式默认关闭。

通过 enableBatterySaverLocked(/*enable*/ true, /*manual*/ true, BatterySaverController.REASON_MANUAL_ON); 打开省电模式,然后把状态切换为 STATE_MANUAL_ON。对于每一次状态切换,我们都要注意,因此这会影响下一次状态切换。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有