大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全家桶1年46,售后保障稳定
1. 电池电量提醒
1.1 未充电提醒
- 若没有预估时间,则提示显示电池百分比
- 若预估时间小于7分钟,则提示手机可能即将关机
- 若预估时间小于15分钟,则提示剩余电池续航时间不到15分钟
- 若15分钟<预估时间<1天,则提示估计大约还能用到xx h, xx min, xx sec
- 若预估时间大于1天,则提示大约还可使用 1 days, x hr, x min, x sec
- 若预估时间大于2天,则提示电量剩余使用时间超过 x 天
1.2 充电提醒
- 若没有预估充满电时间,则默认显示:xx%电量,正在充电
- 若预估充电时间大于0且未充满电,显示还需 xx,充满电
2. 源码
2.0 PowerUsageBase.refreshUi
package com.android.settings.fuelgauge;
/**
* Common base class for things that need to show the battery usage graph.
*/
public abstract class PowerUsageBase extends DashboardFragment {
protected abstract void refreshUi(@BatteryUpdateType int refreshType);
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
mStatsHelper.create(icicle);
setHasOptionsMenu(true);
mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(getContext());
mBatteryBroadcastReceiver.setBatteryChangedListener(type -> {
restartBatteryStatsLoader(type);
});
}
/**
* {@link android.app.LoaderManager.LoaderCallbacks} for {@link PowerUsageBase} to load
* the {@link BatteryStatsHelper}
*/
public class PowerLoaderCallback implements LoaderManager.LoaderCallbacks<BatteryStatsHelper> {
private int mRefreshType;
@Override
public Loader<BatteryStatsHelper> onCreateLoader(int id,
Bundle args) {
mRefreshType = args.getInt(KEY_REFRESH_TYPE);
return new BatteryStatsHelperLoader(getContext());
}
@Override
public void onLoadFinished(Loader<BatteryStatsHelper> loader,
BatteryStatsHelper statsHelper) {
mStatsHelper = statsHelper;
refreshUi(mRefreshType);
}
@Override
public void onLoaderReset(Loader<BatteryStatsHelper> loader) {
}
}
2.1 PowerUsageSummary.refreshUi
package com.android.settings.fuelgauge;
/**
* Displays a list of apps and subsystems that consume power, ordered by how much power was
* consumed since the last time it was unplugged.
*/
public class PowerUsageSummary extends PowerUsageBase implements OnLongClickListener,
BatteryTipPreferenceController.BatteryTipListener {
protected void refreshUi(@BatteryUpdateType int refreshType) {
final Context context = getContext();
if (context == null) {
return;
}
...
restartBatteryTipLoader
}
// 手动点击事件
@Override
public void onBatteryTipHandled(BatteryTip batteryTip) {
restartBatteryTipLoader();
}
@VisibleForTesting
void restartBatteryTipLoader() {
getLoaderManager().restartLoader(BATTERY_TIP_LOADER, Bundle.EMPTY, mBatteryTipsCallbacks);
}
private LoaderManager.LoaderCallbacks<List<BatteryTip>> mBatteryTipsCallbacks =
new LoaderManager.LoaderCallbacks<List<BatteryTip>>() {
@Override
public Loader<List<BatteryTip>> onCreateLoader(int id, Bundle args) {
return new BatteryTipLoader(getContext(), mStatsHelper);
}
@Override
public void onLoadFinished(Loader<List<BatteryTip>> loader,
List<BatteryTip> data) {
mBatteryTipPreferenceController.updateBatteryTips(data);
}
@Override
public void onLoaderReset(Loader<List<BatteryTip>> loader) {
}
};
2.2 BatteryUtils.getBatteryInfo
package com.android.settings.fuelgauge.batterytip;
/**
* Loader to compute and return a battery tip list. It will always return a full length list even
* though some tips may have state {@code BaseBatteryTip.StateType.INVISIBLE}.
*/
public class BatteryTipLoader extends AsyncLoader<List<BatteryTip>> {
private static final String TAG = "BatteryTipLoader";
@Override
public List<BatteryTip> loadInBackground() {
if (USE_FAKE_DATA) {
return getFakeData();
}
final BatteryInfo batteryInfo = mBatteryUtils.getBatteryInfo(mBatteryStatsHelper, TAG);
2.3 BatteryUtils.getBatteryInfo
- BatteryUtils.getInstance.getBatteryInfo
- mBatteryUtils.getBatteryInfo
package com.android.settings.fuelgauge;
/**
* Utils for battery operation
*/
public class BatteryUtils {
@WorkerThread
public BatteryInfo getBatteryInfo(final BatteryStatsHelper statsHelper, final String tag) {
final long startTime = System.currentTimeMillis();
// Stuff we always need to get BatteryInfo
// 获取电池广播
final Intent batteryBroadcast = mContext.registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
// 获取当前时间,并转换为us单位
final long elapsedRealtimeUs = PowerUtil.convertMsToUs(
SystemClock.elapsedRealtime());
final BatteryStats stats = statsHelper.getStats();
BatteryInfo batteryInfo;
final Estimate estimate;
// Get enhanced prediction if available
if (mPowerUsageFeatureProvider != null &&
mPowerUsageFeatureProvider.isEnhancedBatteryPredictionEnabled(mContext)) {// 这里默认为false,这里为基于用户使用
estimate = mPowerUsageFeatureProvider.getEnhancedBatteryPrediction(mContext);
} else {
// 预估时间对象
estimate = new Estimate(
// 预估时间
PowerUtil.convertUsToMs(stats.computeBatteryTimeRemaining(elapsedRealtimeUs)),
// 不基于用户使用
false /* isBasedOnUsage */,
Estimate.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
}
BatteryUtils.logRuntime(tag, "BatteryInfoLoader post query", startTime);
// 参数(context, 电池广播,电池使用状态,预估时间,当前时间,长字符串显示)
batteryInfo = BatteryInfo.getBatteryInfo(mContext, batteryBroadcast, stats,
estimate, elapsedRealtimeUs, false /* shortString */);
BatteryUtils.logRuntime(tag, "BatteryInfoLoader.loadInBackground", startTime);
return batteryInfo;
}
2.3.1 PowerUsageFeatureProvider.isEnhancedBatteryPredictionEnabled
package com.android.settings.fuelgauge;
public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider {
@Override
public boolean isEnhancedBatteryPredictionEnabled(Context context) {
return false;
}
2.3.2 Estimate 对象类
package com.android.settings.fuelgauge;
public class Estimate {
// Value to indicate averageTimeToDischarge could not be obtained
public static final int AVERAGE_TIME_TO_DISCHARGE_UNKNOWN = -1;
public final long estimateMillis;
public final boolean isBasedOnUsage;
public final long averageDischargeTime;
public Estimate(long estimateMillis, boolean isBasedOnUsage,
long averageDischargeTime) {
this.estimateMillis = estimateMillis;
this.isBasedOnUsage = isBasedOnUsage;
this.averageDischargeTime = averageDischargeTime;
}
}
2.3.3 computeBatteryTimeRemaining
- frameworks/base/core/java/android/os/BatteryStats.java
/**
* Compute an approximation for how much run time (in microseconds) is remaining on
* the battery. Returns -1 if no time can be computed: either there is not
* enough current data to make a decision, or the battery is currently
* charging.
*
* @param curTime The current elepsed realtime in microseconds.
*/
public abstract long computeBatteryTimeRemaining(long curTime);
- frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
public long computeBatteryTimeRemaining() {
synchronized (mStats) {
long time = mStats.computeBatteryTimeRemaining(SystemClock.elapsedRealtime());
return time >= 0 ? (time/1000) : time;
}
}
- frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
@Override
public long computeBatteryTimeRemaining(long curTime) {
if (!mOnBattery) {
return -1;
}
/* Simple implementation just looks at the average discharge per level across the
entire sample period.
int discharge = (getLowDischargeAmountSinceCharge()+getHighDischargeAmountSinceCharge())/2;
if (discharge < 2) {
return -1;
}
long duration = computeBatteryRealtime(curTime, STATS_SINCE_CHARGED);
if (duration < 1000*1000) {
return -1;
}
long usPerLevel = duration/discharge;
return usPerLevel * mCurrentBatteryLevel;
*/
if (mDischargeStepTracker.mNumStepDurations < 1) {
return -1;
}
long msPerLevel = mDischargeStepTracker.computeTimePerLevel();
if (msPerLevel <= 0) {
return -1;
}
return (msPerLevel * mCurrentBatteryLevel) * 1000;
}
@Override
public long computeBatteryRealtime(long curTime, int which) {
return mOnBatteryTimeBase.computeRealtime(curTime, which);
}
2.4 BatteryInfo.getBatteryInfo
package com.android.settings.fuelgauge;
public class BatteryInfo {
// 参数(context, 电池广播,电池使用状态,预估时间,当前时间,长字符串显示)
@WorkerThread
public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
BatteryStats stats, Estimate estimate, long elapsedRealtimeUs, boolean shortString) {
final long startTime = System.currentTimeMillis();
BatteryInfo info = new BatteryInfo();
info.mStats = stats;
info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
info.batteryPercentString = Utils.formatPercentage(info.batteryLevel);
info.mCharging = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
info.averageTimeToDischarge = estimate.averageDischargeTime;
final Resources resources = context.getResources();
info.statusLabel = Utils.getBatteryStatus(resources, batteryBroadcast);
if (!info.mCharging) {
// 未充电
updateBatteryInfoDischarging(context, shortString, estimate, info);
} else {
// 充电
updateBatteryInfoCharging(context, batteryBroadcast, stats, elapsedRealtimeUs, info);
}
BatteryUtils.logRuntime(LOG_TAG, "time for getBatteryInfo", startTime);
return info;
}
2.5 未充电 BatteryInfo.updateBatteryInfoDischarging
package com.android.settings.fuelgauge;
public class BatteryInfo {
private static void updateBatteryInfoDischarging(Context context, boolean shortString,
Estimate estimate, BatteryInfo info) {
// 预估时间
final long drainTimeUs = PowerUtil.convertMsToUs(estimate.estimateMillis);
// 预估时间大于0,其中-1为缺省值
if (drainTimeUs > 0) {
info.remainingTimeUs = drainTimeUs;
// 参数:context, 预估时间,电池百分比字符串(null),基于用户使用(false)
info.remainingLabel = PowerUtil.getBatteryRemainingStringFormatted(
context,
PowerUtil.convertUsToMs(drainTimeUs),
null /* percentageString */,
estimate.isBasedOnUsage && !shortString
);
// 参数:context, 预估时间,电池百分比字符串(null),基于用户使用(false)
info.chargeLabel = PowerUtil.getBatteryRemainingStringFormatted(
context,
PowerUtil.convertUsToMs(drainTimeUs),
info.batteryPercentString,
estimate.isBasedOnUsage && !shortString
);
} else {
info.remainingLabel = null;
info.chargeLabel = info.batteryPercentString;
}
}
2.5.1 PowerUtil.getBatteryRemainingStringFormatted
- frameworks/base/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
private static final long SEVEN_MINUTES_MILLIS = TimeUnit.MINUTES.toMillis(7);
private static final long FIFTEEN_MINUTES_MILLIS = TimeUnit.MINUTES.toMillis(15);
private static final long ONE_DAY_MILLIS = TimeUnit.DAYS.toMillis(1);
private static final long TWO_DAYS_MILLIS = TimeUnit.DAYS.toMillis(2);
private static final long ONE_HOUR_MILLIS = TimeUnit.HOURS.toMillis(1);
package com.android.settingslib.utils;
/** Utility class for keeping power related strings consistent**/
public class PowerUtil {
/**
* This method produces the text used in various places throughout the system to describe the
* remaining battery life of the phone in a consistent manner.
*
* @param context
* @param drainTimeMs The estimated time remaining before the phone dies in milliseconds.
* @param percentageString An optional percentage of battery remaining string.
* @param basedOnUsage Whether this estimate is based on usage or simple extrapolation.
* @return a properly formatted and localized string describing how much time remains
* before the battery runs out.
*/
public static String getBatteryRemainingStringFormatted(Context context, long drainTimeMs,
@Nullable String percentageString, boolean basedOnUsage) {
if (drainTimeMs > 0) {
if (drainTimeMs <= SEVEN_MINUTES_MILLIS) {
// show a imminent shutdown warning if less than 7 minutes remain
return getShutdownImminentString(context, percentageString);
} else if (drainTimeMs <= FIFTEEN_MINUTES_MILLIS) {
// show a less than 15 min remaining warning if appropriate
CharSequence timeString = StringUtil.formatElapsedTime(context,
FIFTEEN_MINUTES_MILLIS,
false /* withSeconds */);
return getUnderFifteenString(context, timeString, percentageString);
} else if (drainTimeMs >= TWO_DAYS_MILLIS) {
// just say more than two day if over 48 hours
return getMoreThanTwoDaysString(context, percentageString);
} else if (drainTimeMs >= ONE_DAY_MILLIS) {
// show remaining days & hours if more than a day
return getMoreThanOneDayString(context, drainTimeMs,
percentageString, basedOnUsage);
} else {
// show the time of day we think you'll run out
return getRegularTimeRemainingString(context, drainTimeMs,
percentageString, basedOnUsage);
}
}
return null;
}
2.5.1.1 getShutdownImminentString
为充电时,当预估时间小于7分钟,则提示手机可能即将关机
private static String getShutdownImminentString(Context context, String percentageString) {
return TextUtils.isEmpty(percentageString)
? context.getString(R.string.power_remaining_duration_only_shutdown_imminent)
: context.getString(
R.string.power_remaining_duration_shutdown_imminent,
percentageString);
}
<string name="power_remaining_duration_only_shutdown_imminent" product="default" msgid="1181059207608751924">"手机可能即将关机"</string>
<string name="power_remaining_duration_shutdown_imminent" product="default" msgid="3090926004324573908">"手机可能即将关机 (<xliff:g id="LEVEL">%1$s</xliff:g>)"</string>
2.5.1.2 getUnderFifteenString
为充电时,当预估时间小于15分钟,则提示剩余电池续航时间不到15分钟
<string name="power_remaining_less_than_duration_only" msgid="5996752448813295329">"剩余电池续航时间不到 <xliff:g id="THRESHOLD">%1$s</xliff:g>"</string>
private static String getUnderFifteenString(Context context, CharSequence timeString,
String percentageString) {
return TextUtils.isEmpty(percentageString)
? context.getString(R.string.power_remaining_less_than_duration_only, timeString)
: context.getString(
R.string.power_remaining_less_than_duration,
timeString,
percentageString);
}
2.5.1.3 getMoreThanTwoDaysString
为充电时,当预估时间大于1天,则提示电量剩余使用时间超过 x 天
<string name="power_remaining_only_more_than_subtext" msgid="8931654680569617380">"电量剩余使用时间超过 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
private static String getMoreThanTwoDaysString(Context context, String percentageString) {
final Locale currentLocale = context.getResources().getConfiguration().getLocales().get(0);
final MeasureFormat frmt = MeasureFormat.getInstance(currentLocale, FormatWidth.SHORT);
final Measure daysMeasure = new Measure(2, MeasureUnit.DAY);
return TextUtils.isEmpty(percentageString)
? context.getString(R.string.power_remaining_only_more_than_subtext,
frmt.formatMeasures(daysMeasure))
: context.getString(
R.string.power_remaining_more_than_subtext,
frmt.formatMeasures(daysMeasure),
percentageString);
}
2.5.1.4 getMoreThanOneDayString
为充电时,当预估时间大于1天,则提示大约还可使用 1 days, 5 hr, 40 min, 29 sec
<string name="power_remaining_duration_only_enhanced" msgid="4189311599812296592">"根据您的使用情况,大约还可使用 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
<string name="power_remaining_duration_only" msgid="6123167166221295462">"大约还可使用 <xliff:g id="TIME_REMAINING">%1$s</xliff:g>"</string>
private static String getMoreThanOneDayString(Context context, long drainTimeMs,
String percentageString, boolean basedOnUsage) {
final long roundedTimeMs = roundTimeToNearestThreshold(drainTimeMs, ONE_HOUR_MILLIS);
CharSequence timeString = StringUtil.formatElapsedTime(context,
roundedTimeMs,
false /* withSeconds */);
if (TextUtils.isEmpty(percentageString)) {
int id = basedOnUsage
? R.string.power_remaining_duration_only_enhanced
: R.string.power_remaining_duration_only;
return context.getString(id, timeString);
} else {
int id = basedOnUsage
? R.string.power_discharging_duration_enhanced
: R.string.power_discharging_duration;
return context.getString(id, timeString, percentageString);
}
}
时间转化
package com.android.settingslib.utils;
/** Utility class for generally useful string methods **/
public class StringUtil {
/**
* Returns elapsed time for the given millis, in the following format:
* 2 days, 5 hr, 40 min, 29 sec
*
* @param context the application context
* @param millis the elapsed time in milli seconds
* @param withSeconds include seconds?
* @return the formatted elapsed time
*/
public static CharSequence formatElapsedTime(Context context, double millis,
boolean withSeconds) {
SpannableStringBuilder sb = new SpannableStringBuilder();
int seconds = (int) Math.floor(millis / 1000);
if (!withSeconds) {
// Round up.
seconds += 30;
}
int days = 0, hours = 0, minutes = 0;
if (seconds >= SECONDS_PER_DAY) {
days = seconds / SECONDS_PER_DAY;
seconds -= days * SECONDS_PER_DAY;
}
if (seconds >= SECONDS_PER_HOUR) {
hours = seconds / SECONDS_PER_HOUR;
seconds -= hours * SECONDS_PER_HOUR;
}
if (seconds >= SECONDS_PER_MINUTE) {
minutes = seconds / SECONDS_PER_MINUTE;
seconds -= minutes * SECONDS_PER_MINUTE;
}
final ArrayList<Measure> measureList = new ArrayList(4);
if (days > 0) {
measureList.add(new Measure(days, MeasureUnit.DAY));
}
if (hours > 0) {
measureList.add(new Measure(hours, MeasureUnit.HOUR));
}
if (minutes > 0) {
measureList.add(new Measure(minutes, MeasureUnit.MINUTE));
}
if (withSeconds && seconds > 0) {
measureList.add(new Measure(seconds, MeasureUnit.SECOND));
}
if (measureList.size() == 0) {
// Everything addable was zero, so nothing was added. We add a zero.
measureList.add(new Measure(0, withSeconds ? MeasureUnit.SECOND : MeasureUnit.MINUTE));
}
final Measure[] measureArray = measureList.toArray(new Measure[measureList.size()]);
final Locale locale = context.getResources().getConfiguration().locale;
final MeasureFormat measureFormat = MeasureFormat.getInstance(
locale, FormatWidth.SHORT);
sb.append(measureFormat.formatMeasures(measureArray));
if (measureArray.length == 1 && MeasureUnit.MINUTE.equals(measureArray[0].getUnit())) {
// Add ttsSpan if it only have minute value, because it will be read as "meters"
final TtsSpan ttsSpan = new TtsSpan.MeasureBuilder().setNumber(minutes)
.setUnit("minute").build();
sb.setSpan(ttsSpan, 0, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return sb;
}
2.5.1.5 getRegularTimeRemainingString
为充电时,当预估时间大于15分钟小于1天,则提示估计大约还能用到xx h, xx min, xx sec
<string name="power_discharge_by_only" msgid="107616694963545745">"估计大约还能用到<xliff:g id="TIME">%1$s</xliff:g>"</string>
private static String getRegularTimeRemainingString(Context context, long drainTimeMs,
String percentageString, boolean basedOnUsage) {
// Get the time of day we think device will die rounded to the nearest 15 min.
final long roundedTimeOfDayMs =
roundTimeToNearestThreshold(
System.currentTimeMillis() + drainTimeMs,
FIFTEEN_MINUTES_MILLIS);
// convert the time to a properly formatted string.
String skeleton = android.text.format.DateFormat.getTimeFormatString(context);
DateFormat fmt = DateFormat.getInstanceForSkeleton(skeleton);
Date date = Date.from(Instant.ofEpochMilli(roundedTimeOfDayMs));
CharSequence timeString = fmt.format(date);
if (TextUtils.isEmpty(percentageString)) {
int id = basedOnUsage
? R.string.power_discharge_by_only_enhanced
: R.string.power_discharge_by_only;
return context.getString(id, timeString);
} else {
int id = basedOnUsage
? R.string.power_discharge_by_enhanced
: R.string.power_discharge_by;
return context.getString(id, timeString, percentageString);
}
}
2.6 充电 BatteryInfo.updateBatteryInfoCharging
<string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"还需 <xliff:g id="TIME">%1$s</xliff:g>充满电"</string>
<string name="battery_info_status_charging_lower" msgid="8689770213898117994">"正在充电"</string>
package com.android.settings.fuelgauge;
public class BatteryInfo {
private static void updateBatteryInfoCharging(Context context, Intent batteryBroadcast,
BatteryStats stats, long elapsedRealtimeUs, BatteryInfo info) {
final Resources resources = context.getResources();
// 预估充电时间
final long chargeTime = stats.computeChargeTimeRemaining(elapsedRealtimeUs);
// 电池状态
final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
info.discharging = false;
// 预估充电时间大于0且未充满电,则显示还需 xx,充满电
if (chargeTime > 0 && status != BatteryManager.BATTERY_STATUS_FULL) {
info.remainingTimeUs = chargeTime;
CharSequence timeString = StringUtil.formatElapsedTime(context,
PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */);
int resId = R.string.power_charging_duration;
info.remainingLabel = context.getString(
R.string.power_remaining_charging_duration_only, timeString);
info.chargeLabel = context.getString(resId, info.batteryPercentString, timeString);
// 默认显示:xx%电量,正在充电
} else {
final String chargeStatusLabel = resources.getString(
R.string.battery_info_status_charging_lower);
info.remainingLabel = null;
info.chargeLabel = info.batteryLevel == 100 ? info.batteryPercentString :
resources.getString(R.string.power_charging, info.batteryPercentString,
chargeStatusLabel);
}
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/206775.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...