Format battery java code

After this CL, we can follow Guideline:go/hc-mainline-dev#format-code to keep java format consistent.

Test: manual
Bug: 304439460
Change-Id: I5bb77f81b0bd9be618e34942eaaee8296bc42796
This commit is contained in:
Jun Lan
2023-11-02 18:55:52 +08:00
parent da70c86bda
commit cca804e1ed
127 changed files with 4343 additions and 3581 deletions

View File

@@ -61,15 +61,15 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Power usage detail fragment for each app, this fragment contains
*
* 1. Detail battery usage information for app(i.e. usage time, usage amount)
* Power usage detail fragment for each app, this fragment contains <br>
* <br>
* 1. Detail battery usage information for app(i.e. usage time, usage amount) <br>
* 2. Battery related controls for app(i.e uninstall, force stop)
*/
public class AdvancedPowerUsageDetail extends DashboardFragment implements
ButtonActionDialogFragment.AppButtonsDialogListener,
Preference.OnPreferenceClickListener,
Preference.OnPreferenceChangeListener {
public class AdvancedPowerUsageDetail extends DashboardFragment
implements ButtonActionDialogFragment.AppButtonsDialogListener,
Preference.OnPreferenceClickListener,
Preference.OnPreferenceChangeListener {
public static final String TAG = "AdvancedPowerDetail";
public static final String EXTRA_UID = "extra_uid";
public static final String EXTRA_PACKAGE_NAME = "extra_package_name";
@@ -96,23 +96,17 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
private AppButtonsPreferenceController mAppButtonsPreferenceController;
private PowerUsageTimeController mPowerUsageTimeController;
@VisibleForTesting
LayoutPreference mHeaderPreference;
@VisibleForTesting
ApplicationsState mState;
@VisibleForTesting
ApplicationsState.AppEntry mAppEntry;
@VisibleForTesting
BatteryOptimizeUtils mBatteryOptimizeUtils;
@VisibleForTesting
PrimarySwitchPreference mAllowBackgroundUsagePreference;
@VisibleForTesting
@BatteryOptimizeUtils.OptimizationMode
@VisibleForTesting LayoutPreference mHeaderPreference;
@VisibleForTesting ApplicationsState mState;
@VisibleForTesting ApplicationsState.AppEntry mAppEntry;
@VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
@VisibleForTesting PrimarySwitchPreference mAllowBackgroundUsagePreference;
@VisibleForTesting @BatteryOptimizeUtils.OptimizationMode
int mOptimizationMode = BatteryOptimizeUtils.MODE_UNKNOWN;
@VisibleForTesting
BackupManager mBackupManager;
@VisibleForTesting
StringBuilder mLogStringBuilder;
@VisibleForTesting BackupManager mBackupManager;
@VisibleForTesting StringBuilder mLogStringBuilder;
// A wrapper class to carry LaunchBatteryDetailPage required arguments.
private static final class LaunchBatteryDetailPageArgs {
@@ -134,9 +128,14 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
/** Launches battery details page for an individual battery consumer fragment. */
public static void startBatteryDetailPage(
Context context, int sourceMetricsCategory,
BatteryDiffEntry diffEntry, String usagePercent, String slotInformation,
boolean showTimeInformation, String anomalyHintPrefKey, String anomalyHintText) {
Context context,
int sourceMetricsCategory,
BatteryDiffEntry diffEntry,
String usagePercent,
String slotInformation,
boolean showTimeInformation,
String anomalyHintPrefKey,
String anomalyHintText) {
final LaunchBatteryDetailPageArgs launchArgs = new LaunchBatteryDetailPageArgs();
// configure the launch argument.
launchArgs.mUsagePercent = usagePercent;
@@ -159,8 +158,11 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
}
/** Launches battery details page for an individual battery consumer. */
public static void startBatteryDetailPage(Activity caller,
InstrumentedPreferenceFragment fragment, BatteryEntry entry, String usagePercent) {
public static void startBatteryDetailPage(
Activity caller,
InstrumentedPreferenceFragment fragment,
BatteryEntry entry,
String usagePercent) {
final LaunchBatteryDetailPageArgs launchArgs = new LaunchBatteryDetailPageArgs();
// configure the launch argument.
launchArgs.mUsagePercent = usagePercent;
@@ -197,8 +199,10 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
args.putBoolean(EXTRA_SHOW_TIME_INFO, launchArgs.mShowTimeInformation);
args.putString(EXTRA_ANOMALY_HINT_PREF_KEY, launchArgs.mAnomalyHintPrefKey);
args.putString(EXTRA_ANOMALY_HINT_TEXT, launchArgs.mAnomalyHintText);
final int userId = launchArgs.mIsUserEntry ? ActivityManager.getCurrentUser()
: UserHandle.getUserId(launchArgs.mUid);
final int userId =
launchArgs.mIsUserEntry
? ActivityManager.getCurrentUser()
: UserHandle.getUserId(launchArgs.mUid);
new SubSettingLauncher(context)
.setDestination(AdvancedPowerUsageDetail.class.getName())
@@ -209,11 +213,11 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
.launch();
}
/**
* Start packageName's battery detail page.
*/
/** Start packageName's battery detail page. */
public static void startBatteryDetailPage(
Activity caller, Instrumentable instrumentable, String packageName,
Activity caller,
Instrumentable instrumentable,
String packageName,
UserHandle userHandle) {
final Bundle args = new Bundle(3);
final PackageManager packageManager = caller.getPackageManager();
@@ -261,15 +265,18 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
initHeader();
mOptimizationMode = mBatteryOptimizeUtils.getAppOptimizationMode();
initFooter();
mExecutor.execute(() -> {
final String packageName = BatteryUtils
.getLoggingPackageName(getContext(), mBatteryOptimizeUtils.getPackageName());
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
.action(
getContext(),
SettingsEnums.OPEN_APP_BATTERY_USAGE,
packageName);
});
mExecutor.execute(
() -> {
final String packageName =
BatteryUtils.getLoggingPackageName(
getContext(), mBatteryOptimizeUtils.getPackageName());
FeatureFactory.getFeatureFactory()
.getMetricsFeatureProvider()
.action(
getContext(),
SettingsEnums.OPEN_APP_BATTERY_USAGE,
packageName);
});
mLogStringBuilder = new StringBuilder("onResume mode = ").append(mOptimizationMode);
}
@@ -282,22 +289,23 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
mLogStringBuilder.append(", onPause mode = ").append(currentOptimizeMode);
logMetricCategory(currentOptimizeMode);
mExecutor.execute(() -> {
BatteryOptimizeLogUtils.writeLog(
getContext().getApplicationContext(),
Action.LEAVE,
BatteryOptimizeLogUtils.getPackageNameWithUserId(
mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()),
mLogStringBuilder.toString());
});
mExecutor.execute(
() -> {
BatteryOptimizeLogUtils.writeLog(
getContext().getApplicationContext(),
Action.LEAVE,
BatteryOptimizeLogUtils.getPackageNameWithUserId(
mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()),
mLogStringBuilder.toString());
});
Log.d(TAG, "Leave with mode: " + currentOptimizeMode);
}
@VisibleForTesting
void notifyBackupManager() {
if (mOptimizationMode != mBatteryOptimizeUtils.getAppOptimizationMode()) {
final BackupManager backupManager = mBackupManager != null
? mBackupManager : new BackupManager(getContext());
final BackupManager backupManager =
mBackupManager != null ? mBackupManager : new BackupManager(getContext());
backupManager.dataChanged();
}
}
@@ -307,10 +315,11 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
final View appSnippet = mHeaderPreference.findViewById(R.id.entity_header);
final Activity context = getActivity();
final Bundle bundle = getArguments();
EntityHeaderController controller = EntityHeaderController
.newInstance(context, this, appSnippet)
.setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
EntityHeaderController.ActionType.ACTION_NONE);
EntityHeaderController controller =
EntityHeaderController.newInstance(context, this, appSnippet)
.setButtonActions(
EntityHeaderController.ActionType.ACTION_NONE,
EntityHeaderController.ActionType.ACTION_NONE);
if (mAppEntry == null) {
controller.setLabel(bundle.getString(EXTRA_LABEL));
@@ -334,8 +343,12 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
final long backgroundTimeMs = bundle.getLong(EXTRA_BACKGROUND_TIME);
final String anomalyHintPrefKey = bundle.getString(EXTRA_ANOMALY_HINT_PREF_KEY);
final String anomalyHintText = bundle.getString(EXTRA_ANOMALY_HINT_TEXT);
mPowerUsageTimeController.handleScreenTimeUpdated(slotTime, screenOnTimeInMs,
backgroundTimeMs, anomalyHintPrefKey, anomalyHintText);
mPowerUsageTimeController.handleScreenTimeUpdated(
slotTime,
screenOnTimeInMs,
backgroundTimeMs,
anomalyHintPrefKey,
anomalyHintText);
}
controller.done(true /* rebindActions */);
}
@@ -387,9 +400,15 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
final int uid = bundle.getInt(EXTRA_UID, 0);
final String packageName = bundle.getString(EXTRA_PACKAGE_NAME);
mAppButtonsPreferenceController = new AppButtonsPreferenceController(
(SettingsActivity) getActivity(), this, getSettingsLifecycle(),
packageName, mState, REQUEST_UNINSTALL, REQUEST_REMOVE_DEVICE_ADMIN);
mAppButtonsPreferenceController =
new AppButtonsPreferenceController(
(SettingsActivity) getActivity(),
this,
getSettingsLifecycle(),
packageName,
mState,
REQUEST_UNINSTALL,
REQUEST_REMOVE_DEVICE_ADMIN);
if (bundle.getBoolean(EXTRA_SHOW_TIME_INFO, false)) {
mPowerUsageTimeController = new PowerUsageTimeController(getContext());
controllers.add(mPowerUsageTimeController);
@@ -461,17 +480,20 @@ public class AdvancedPowerUsageDetail extends DashboardFragment implements
return;
}
int finalMetricCategory = metricCategory;
mExecutor.execute(() -> {
String packageName = BatteryUtils
.getLoggingPackageName(getContext(), mBatteryOptimizeUtils.getPackageName());
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
.action(
/* attribution */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
/* action */ finalMetricCategory,
/* pageId */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
packageName,
getArguments().getInt(EXTRA_POWER_USAGE_AMOUNT));
});
mExecutor.execute(
() -> {
String packageName =
BatteryUtils.getLoggingPackageName(
getContext(), mBatteryOptimizeUtils.getPackageName());
FeatureFactory.getFeatureFactory()
.getMetricsFeatureProvider()
.action(
/* attribution */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
/* action */ finalMetricCategory,
/* pageId */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
packageName,
getArguments().getInt(EXTRA_POWER_USAGE_AMOUNT));
});
}
private void onCreateBackgroundUsageState(String packageName) {

View File

@@ -29,14 +29,11 @@ import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.SubSettingLauncher;
/**
* Trampoline activity for launching the {@link AdvancedPowerUsageDetail} fragment.
*/
/** Trampoline activity for launching the {@link AdvancedPowerUsageDetail} fragment. */
public class AdvancedPowerUsageDetailActivity extends AppCompatActivity {
private static final String TAG = "AdvancedPowerDetailActivity";

View File

@@ -53,8 +53,9 @@ public class AllowBackgroundPreferenceController extends AbstractPreferenceContr
public void updateState(Preference preference) {
preference.setEnabled(mBatteryOptimizeUtils.isOptimizeModeMutable());
final boolean isAllowBackground = mBatteryOptimizeUtils.getAppOptimizationMode()
!= BatteryOptimizeUtils.MODE_RESTRICTED;
final boolean isAllowBackground =
mBatteryOptimizeUtils.getAppOptimizationMode()
!= BatteryOptimizeUtils.MODE_RESTRICTED;
setChecked(preference, isAllowBackground);
}

View File

@@ -24,11 +24,9 @@ import androidx.preference.TwoStatePreference;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory;
/**
* Controller to change and update the auto restriction toggle
*/
public class AutoRestrictionPreferenceController extends BasePreferenceController implements
Preference.OnPreferenceChangeListener {
/** Controller to change and update the auto restriction toggle */
public class AutoRestrictionPreferenceController extends BasePreferenceController
implements Preference.OnPreferenceChangeListener {
private static final String KEY_SMART_BATTERY = "auto_restriction";
private static final int ON = 1;
private static final int OFF = 0;
@@ -50,15 +48,20 @@ public class AutoRestrictionPreferenceController extends BasePreferenceControlle
@Override
public void updateState(Preference preference) {
super.updateState(preference);
final boolean smartBatteryOn = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.APP_AUTO_RESTRICTION_ENABLED, ON) == ON;
final boolean smartBatteryOn =
Settings.Global.getInt(
mContext.getContentResolver(),
Settings.Global.APP_AUTO_RESTRICTION_ENABLED,
ON)
== ON;
((TwoStatePreference) preference).setChecked(smartBatteryOn);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean smartBatteryOn = (Boolean) newValue;
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.putInt(
mContext.getContentResolver(),
Settings.Global.APP_AUTO_RESTRICTION_ENABLED,
smartBatteryOn ? ON : OFF);
return true;

View File

@@ -63,13 +63,15 @@ public class BatteryActiveView extends View {
return;
}
mPaint.setColor(color);
canvas.drawRect(start / period * getWidth(), 0, end / period * getWidth(), getHeight(),
mPaint);
canvas.drawRect(
start / period * getWidth(), 0, end / period * getWidth(), getHeight(), mPaint);
}
public interface BatteryActiveProvider {
boolean hasData();
long getPeriod();
SparseIntArray getColorArray();
}
}

View File

@@ -52,6 +52,7 @@ import java.util.List;
public final class BatteryBackupHelper implements BackupHelper {
/** An inditifier for {@link BackupHelper}. */
public static final String TAG = "BatteryBackupHelper";
// Definition for the device build information.
public static final String KEY_BUILD_BRAND = "device_build_brand";
public static final String KEY_BUILD_PRODUCT = "device_build_product";
@@ -70,17 +71,12 @@ public final class BatteryBackupHelper implements BackupHelper {
static final String DELIMITER_MODE = ":";
static final String KEY_OPTIMIZATION_LIST = "optimization_mode_list";
@VisibleForTesting
ArraySet<ApplicationInfo> mTestApplicationInfoList = null;
@VisibleForTesting ArraySet<ApplicationInfo> mTestApplicationInfoList = null;
@VisibleForTesting
PowerAllowlistBackend mPowerAllowlistBackend;
@VisibleForTesting
IDeviceIdleController mIDeviceIdleController;
@VisibleForTesting
IPackageManager mIPackageManager;
@VisibleForTesting
BatteryOptimizeUtils mBatteryOptimizeUtils;
@VisibleForTesting PowerAllowlistBackend mPowerAllowlistBackend;
@VisibleForTesting IDeviceIdleController mIDeviceIdleController;
@VisibleForTesting IPackageManager mIPackageManager;
@VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
private byte[] mOptimizationModeBytes;
private boolean mVerifyMigrateConfiguration = false;
@@ -95,8 +91,8 @@ public final class BatteryBackupHelper implements BackupHelper {
}
@Override
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
public void performBackup(
ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) {
if (!isOwner() || data == null) {
Log.w(TAG, "ignore performBackup() for non-owner or empty data");
return;
@@ -149,8 +145,7 @@ public final class BatteryBackupHelper implements BackupHelper {
}
@Override
public void writeNewStateDescription(ParcelFileDescriptor newState) {
}
public void writeNewStateDescription(ParcelFileDescriptor newState) {}
private List<String> getFullPowerList() {
final long timestamp = System.currentTimeMillis();
@@ -166,8 +161,11 @@ public final class BatteryBackupHelper implements BackupHelper {
Log.w(TAG, "no data found in the getFullPowerList()");
return new ArrayList<>();
}
Log.d(TAG, String.format("getFullPowerList() size=%d in %d/ms",
allowlistedApps.length, (System.currentTimeMillis() - timestamp)));
Log.d(
TAG,
String.format(
"getFullPowerList() size=%d in %d/ms",
allowlistedApps.length, (System.currentTimeMillis() - timestamp)));
return Arrays.asList(allowlistedApps);
}
@@ -187,27 +185,34 @@ public final class BatteryBackupHelper implements BackupHelper {
for (ApplicationInfo info : applications) {
final int mode = BatteryOptimizeUtils.getMode(appOps, info.uid, info.packageName);
@BatteryOptimizeUtils.OptimizationMode
final int optimizationMode = BatteryOptimizeUtils.getAppOptimizationMode(
mode, allowlistedApps.contains(info.packageName));
final int optimizationMode =
BatteryOptimizeUtils.getAppOptimizationMode(
mode, allowlistedApps.contains(info.packageName));
// Ignores default optimized/unknown state or system/default apps.
if (optimizationMode == BatteryOptimizeUtils.MODE_OPTIMIZED
|| optimizationMode == BatteryOptimizeUtils.MODE_UNKNOWN
|| isSystemOrDefaultApp(info.packageName, info.uid)) {
continue;
}
final String packageOptimizeMode =
info.packageName + DELIMITER_MODE + optimizationMode;
final String packageOptimizeMode = info.packageName + DELIMITER_MODE + optimizationMode;
builder.append(packageOptimizeMode + DELIMITER);
Log.d(TAG, "backupOptimizationMode: " + packageOptimizeMode);
BatteryOptimizeLogUtils.writeLog(
sharedPreferences, Action.BACKUP, info.packageName,
sharedPreferences,
Action.BACKUP,
info.packageName,
/* actionDescription */ "mode: " + optimizationMode);
backupCount++;
}
writeBackupData(data, KEY_OPTIMIZATION_LIST, builder.toString());
Log.d(TAG, String.format("backup getInstalledApplications():%d count=%d in %d/ms",
applications.size(), backupCount, (System.currentTimeMillis() - timestamp)));
Log.d(
TAG,
String.format(
"backup getInstalledApplications():%d count=%d in %d/ms",
applications.size(),
backupCount,
(System.currentTimeMillis() - timestamp)));
}
@VisibleForTesting
@@ -225,8 +230,8 @@ public final class BatteryBackupHelper implements BackupHelper {
}
int restoreCount = 0;
for (int index = 0; index < appConfigurations.length; index++) {
final String[] results = appConfigurations[index]
.split(BatteryBackupHelper.DELIMITER_MODE);
final String[] results =
appConfigurations[index].split(BatteryBackupHelper.DELIMITER_MODE);
// Example format: com.android.systemui:2 we should have length=2
if (results == null || results.length != 2) {
Log.w(TAG, "invalid raw data found:" + appConfigurations[index]);
@@ -244,15 +249,17 @@ public final class BatteryBackupHelper implements BackupHelper {
try {
optimizationMode = Integer.parseInt(results[1]);
} catch (NumberFormatException e) {
Log.e(TAG, "failed to parse the optimization mode: "
+ appConfigurations[index], e);
Log.e(TAG, "failed to parse the optimization mode: " + appConfigurations[index], e);
continue;
}
restoreOptimizationMode(packageName, optimizationMode);
restoreCount++;
}
Log.d(TAG, String.format("restoreOptimizationMode() count=%d in %d/ms",
restoreCount, (System.currentTimeMillis() - timestamp)));
Log.d(
TAG,
String.format(
"restoreOptimizationMode() count=%d in %d/ms",
restoreCount, (System.currentTimeMillis() - timestamp)));
return restoreCount;
}
@@ -319,8 +326,9 @@ public final class BatteryBackupHelper implements BackupHelper {
if (mIDeviceIdleController != null) {
return mIDeviceIdleController;
}
mIDeviceIdleController = IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(DEVICE_IDLE_SERVICE));
mIDeviceIdleController =
IDeviceIdleController.Stub.asInterface(
ServiceManager.getService(DEVICE_IDLE_SERVICE));
return mIDeviceIdleController;
}
@@ -374,8 +382,7 @@ public final class BatteryBackupHelper implements BackupHelper {
return dataBytes;
}
private static void writeBackupData(
BackupDataOutput data, String dataKey, String dataContent) {
private static void writeBackupData(BackupDataOutput data, String dataKey, String dataContent) {
if (dataContent == null || dataContent.isEmpty()) {
return;
}

View File

@@ -34,19 +34,19 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Use this broadcastReceiver to listen to the battery change and it will invoke
* {@link OnBatteryChangedListener}
* Use this broadcastReceiver to listen to the battery change and it will invoke {@link
* OnBatteryChangedListener}
*/
public class BatteryBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "BatteryBroadcastRcvr";
/**
* Callback if any of the monitored fields has been changed:
*
* Battery level(e.g. 100%->99%)
* Battery status(e.g. plugged->unplugged)
* Battery saver(e.g. off->on)
* Battery health(e.g. good->overheat)
* Callback if any of the monitored fields has been changed: <br>
* <br>
* Battery level(e.g. 100%->99%) Battery status(e.g. plugged->unplugged) <br>
* Battery saver(e.g.off->on) <br>
* Battery health(e.g. good->overheat) <br>
* Battery charging status(e.g. default->long life)
*/
public interface OnBatteryChangedListener {
@@ -54,13 +54,15 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver {
}
@Retention(RetentionPolicy.SOURCE)
@IntDef({BatteryUpdateType.MANUAL,
BatteryUpdateType.BATTERY_LEVEL,
BatteryUpdateType.BATTERY_SAVER,
BatteryUpdateType.BATTERY_STATUS,
BatteryUpdateType.BATTERY_HEALTH,
BatteryUpdateType.CHARGING_STATUS,
BatteryUpdateType.BATTERY_NOT_PRESENT})
@IntDef({
BatteryUpdateType.MANUAL,
BatteryUpdateType.BATTERY_LEVEL,
BatteryUpdateType.BATTERY_SAVER,
BatteryUpdateType.BATTERY_STATUS,
BatteryUpdateType.BATTERY_HEALTH,
BatteryUpdateType.CHARGING_STATUS,
BatteryUpdateType.BATTERY_NOT_PRESENT
})
public @interface BatteryUpdateType {
int MANUAL = 0;
int BATTERY_LEVEL = 1;
@@ -71,14 +73,10 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver {
int BATTERY_NOT_PRESENT = 6;
}
@VisibleForTesting
String mBatteryLevel;
@VisibleForTesting
String mBatteryStatus;
@VisibleForTesting
int mChargingStatus;
@VisibleForTesting
int mBatteryHealth;
@VisibleForTesting String mBatteryLevel;
@VisibleForTesting String mBatteryStatus;
@VisibleForTesting int mChargingStatus;
@VisibleForTesting int mBatteryHealth;
private OnBatteryChangedListener mBatteryListener;
private Context mContext;
@@ -102,8 +100,8 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver {
intentFilter.addAction(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION);
intentFilter.addAction(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED);
final Intent intent = mContext.registerReceiver(this, intentFilter,
Context.RECEIVER_EXPORTED);
final Intent intent =
mContext.registerReceiver(this, intentFilter, Context.RECEIVER_EXPORTED);
updateBatteryStatus(intent, true /* forceUpdate */);
}
@@ -121,10 +119,13 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver {
final String batteryLevel = Utils.getBatteryPercentage(intent);
final String batteryStatus =
Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false);
final int chargingStatus = intent.getIntExtra(
BatteryManager.EXTRA_CHARGING_STATUS, BatteryManager.CHARGING_POLICY_DEFAULT);
final int batteryHealth = intent.getIntExtra(
BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
final int chargingStatus =
intent.getIntExtra(
BatteryManager.EXTRA_CHARGING_STATUS,
BatteryManager.CHARGING_POLICY_DEFAULT);
final int batteryHealth =
intent.getIntExtra(
BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);
Log.d(
TAG,
"Battery changed: level: "
@@ -144,7 +145,7 @@ public class BatteryBroadcastReceiver extends BroadcastReceiver {
mBatteryListener.onBatteryChanged(BatteryUpdateType.CHARGING_STATUS);
} else if (batteryHealth != mBatteryHealth) {
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_HEALTH);
} else if(!batteryLevel.equals(mBatteryLevel)) {
} else if (!batteryLevel.equals(mBatteryLevel)) {
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_LEVEL);
} else if (!batteryStatus.equals(mBatteryStatus)) {
mBatteryListener.onBatteryChanged(BatteryUpdateType.BATTERY_STATUS);

View File

@@ -34,21 +34,16 @@ import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.Utils;
import com.android.settingslib.widget.UsageProgressBarPreference;
/**
* Controller that update the battery header view
*/
/** Controller that update the battery header view */
public class BatteryHeaderPreferenceController extends BasePreferenceController
implements PreferenceControllerMixin, BatteryPreferenceController {
private static final String TAG = "BatteryHeaderPreferenceController";
@VisibleForTesting
static final String KEY_BATTERY_HEADER = "battery_header";
@VisibleForTesting static final String KEY_BATTERY_HEADER = "battery_header";
private static final int BATTERY_MAX_LEVEL = 100;
@VisibleForTesting
BatteryStatusFeatureProvider mBatteryStatusFeatureProvider;
@VisibleForTesting
UsageProgressBarPreference mBatteryUsageProgressBarPref;
@VisibleForTesting BatteryStatusFeatureProvider mBatteryStatusFeatureProvider;
@VisibleForTesting UsageProgressBarPreference mBatteryUsageProgressBarPref;
private BatteryTip mBatteryTip;
private final PowerManager mPowerManager;
@@ -56,8 +51,8 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
public BatteryHeaderPreferenceController(Context context, String key) {
super(context, key);
mPowerManager = context.getSystemService(PowerManager.class);
mBatteryStatusFeatureProvider = FeatureFactory.getFeatureFactory()
.getBatteryStatusFeatureProvider();
mBatteryStatusFeatureProvider =
FeatureFactory.getFeatureFactory().getBatteryStatusFeatureProvider();
}
@Override
@@ -96,12 +91,11 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
R.string.battery_state_and_duration, info.statusLabel, info.remainingLabel);
} else if (mPowerManager.isPowerSaveMode()) {
// Power save mode is on
final String powerSaverOn = mContext.getString(
R.string.battery_tip_early_heads_up_done_title);
final String powerSaverOn =
mContext.getString(R.string.battery_tip_early_heads_up_done_title);
return mContext.getString(
R.string.battery_state_and_duration, powerSaverOn, info.remainingLabel);
} else if (mBatteryTip != null
&& mBatteryTip.getType() == BatteryTip.TipType.LOW_BATTERY) {
} else if (mBatteryTip != null && mBatteryTip.getType() == BatteryTip.TipType.LOW_BATTERY) {
// Low battery state
final String lowBattery = mContext.getString(R.string.low_battery_summary);
return mContext.getString(
@@ -122,9 +116,7 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
mBatteryUsageProgressBarPref.setPercent(info.batteryLevel, BATTERY_MAX_LEVEL);
}
/**
* Callback which receives text for the summary line.
*/
/** Callback which receives text for the summary line. */
public void updateBatteryStatus(String label, BatteryInfo info) {
final CharSequence summary = label != null ? label : generateLabel(info);
mBatteryUsageProgressBarPref.setBottomSummary(summary);
@@ -132,8 +124,8 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
}
public void quickUpdateHeaderPreference() {
Intent batteryBroadcast = com.android.settingslib.fuelgauge.BatteryUtils
.getBatteryIntent(mContext);
Intent batteryBroadcast =
com.android.settingslib.fuelgauge.BatteryUtils.getBatteryIntent(mContext);
final int batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
final boolean discharging =
batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) == 0;
@@ -142,9 +134,7 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
mBatteryUsageProgressBarPref.setPercent(batteryLevel, BATTERY_MAX_LEVEL);
}
/**
* Update summary when battery tips changed.
*/
/** Update summary when battery tips changed. */
public void updateHeaderByBatteryTips(BatteryTip batteryTip, BatteryInfo batteryInfo) {
mBatteryTip = batteryTip;
@@ -154,7 +144,8 @@ public class BatteryHeaderPreferenceController extends BasePreferenceController
}
private CharSequence formatBatteryPercentageText(int batteryLevel) {
return TextUtils.expandTemplate(mContext.getText(R.string.battery_header_title_alternate),
return TextUtils.expandTemplate(
mContext.getText(R.string.battery_header_title_alternate),
NumberFormat.getIntegerInstance().format(batteryLevel));
}
}

View File

@@ -68,93 +68,110 @@ public class BatteryInfo {
public void bindHistory(final UsageView view, BatteryDataParser... parsers) {
final Context context = view.getContext();
BatteryDataParser parser = new BatteryDataParser() {
SparseIntArray points = new SparseIntArray();
long startTime;
int lastTime = -1;
byte lastLevel;
BatteryDataParser parser =
new BatteryDataParser() {
SparseIntArray mPoints = new SparseIntArray();
long mStartTime;
int mLastTime = -1;
byte mLastLevel;
@Override
public void onParsingStarted(long startTime, long endTime) {
this.startTime = startTime;
timePeriod = endTime - startTime;
view.clearPaths();
// Initially configure the graph for history only.
view.configureGraph((int) timePeriod, 100);
}
@Override
public void onParsingStarted(long startTime, long endTime) {
this.mStartTime = startTime;
timePeriod = endTime - startTime;
view.clearPaths();
// Initially configure the graph for history only.
view.configureGraph((int) timePeriod, 100);
}
@Override
public void onDataPoint(long time, HistoryItem record) {
lastTime = (int) time;
lastLevel = record.batteryLevel;
points.put(lastTime, lastLevel);
}
@Override
public void onDataPoint(long time, HistoryItem record) {
mLastTime = (int) time;
mLastLevel = record.batteryLevel;
mPoints.put(mLastTime, mLastLevel);
}
@Override
public void onDataGap() {
if (points.size() > 1) {
view.addPath(points);
}
points.clear();
}
@Override
public void onDataGap() {
if (mPoints.size() > 1) {
view.addPath(mPoints);
}
mPoints.clear();
}
@Override
public void onParsingDone() {
onDataGap();
@Override
public void onParsingDone() {
onDataGap();
// Add projection if we have an estimate.
if (remainingTimeUs != 0) {
PowerUsageFeatureProvider provider =
FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider();
if (!mCharging && provider.isEnhancedBatteryPredictionEnabled(context)) {
points = provider.getEnhancedBatteryPredictionCurve(context, startTime);
} else {
// Linear extrapolation.
if (lastTime >= 0) {
points.put(lastTime, lastLevel);
points.put((int) (timePeriod +
PowerUtil.convertUsToMs(remainingTimeUs)),
mCharging ? 100 : 0);
// Add projection if we have an estimate.
if (remainingTimeUs != 0) {
PowerUsageFeatureProvider provider =
FeatureFactory.getFeatureFactory()
.getPowerUsageFeatureProvider();
if (!mCharging
&& provider.isEnhancedBatteryPredictionEnabled(context)) {
mPoints =
provider.getEnhancedBatteryPredictionCurve(
context, mStartTime);
} else {
// Linear extrapolation.
if (mLastTime >= 0) {
mPoints.put(mLastTime, mLastLevel);
mPoints.put(
(int)
(timePeriod
+ PowerUtil.convertUsToMs(
remainingTimeUs)),
mCharging ? 100 : 0);
}
}
}
// If we have a projection, reconfigure the graph to show it.
if (mPoints != null && mPoints.size() > 0) {
int maxTime = mPoints.keyAt(mPoints.size() - 1);
view.configureGraph(maxTime, 100);
view.addProjectedPath(mPoints);
}
}
}
// If we have a projection, reconfigure the graph to show it.
if (points != null && points.size() > 0) {
int maxTime = points.keyAt(points.size() - 1);
view.configureGraph(maxTime, 100);
view.addProjectedPath(points);
}
}
};
};
BatteryDataParser[] parserList = new BatteryDataParser[parsers.length + 1];
for (int i = 0; i < parsers.length; i++) {
parserList[i] = parsers[i];
}
parserList[parsers.length] = parser;
parseBatteryHistory(parserList);
String timeString = context.getString(com.android.settingslib.R.string.charge_length_format,
Formatter.formatShortElapsedTime(context, timePeriod));
String timeString =
context.getString(
com.android.settingslib.R.string.charge_length_format,
Formatter.formatShortElapsedTime(context, timePeriod));
String remaining = "";
if (remainingTimeUs != 0) {
remaining = context.getString(com.android.settingslib.R.string.remaining_length_format,
Formatter.formatShortElapsedTime(context, remainingTimeUs / 1000));
remaining =
context.getString(
com.android.settingslib.R.string.remaining_length_format,
Formatter.formatShortElapsedTime(context, remainingTimeUs / 1000));
}
view.setBottomLabels(new CharSequence[]{timeString, remaining});
view.setBottomLabels(new CharSequence[] {timeString, remaining});
}
public static void getBatteryInfo(final Context context, final Callback callback,
boolean shortString) {
BatteryInfo.getBatteryInfo(context, callback, /* batteryUsageStats */ null, shortString);
/** Gets battery info */
public static void getBatteryInfo(
final Context context, final Callback callback, boolean shortString) {
BatteryInfo.getBatteryInfo(context, callback, /* batteryUsageStats */ null, shortString);
}
static long getSettingsChargeTimeRemaining(final Context context) {
return Settings.Global.getLong(
context.getContentResolver(),
com.android.settingslib.fuelgauge.BatteryUtils.GLOBAL_TIME_TO_FULL_MILLIS, -1);
com.android.settingslib.fuelgauge.BatteryUtils.GLOBAL_TIME_TO_FULL_MILLIS,
-1);
}
public static void getBatteryInfo(final Context context, final Callback callback,
/** Gets battery info */
public static void getBatteryInfo(
final Context context,
final Callback callback,
@Nullable final BatteryUsageStats batteryUsageStats,
boolean shortString) {
new AsyncTask<Void, Void, BatteryInfo>() {
@@ -166,8 +183,9 @@ public class BatteryInfo {
stats = batteryUsageStats;
} else {
try {
stats = context.getSystemService(BatteryStatsManager.class)
.getBatteryUsageStats();
stats =
context.getSystemService(BatteryStatsManager.class)
.getBatteryUsageStats();
shouldCloseBatteryUsageStats = true;
} catch (RuntimeException e) {
Log.e(TAG, "getBatteryInfo() from getBatteryUsageStats()", e);
@@ -175,8 +193,7 @@ public class BatteryInfo {
stats = new BatteryUsageStats.Builder(new String[0]).build();
}
}
final BatteryInfo batteryInfo =
getBatteryInfo(context, stats, shortString);
final BatteryInfo batteryInfo = getBatteryInfo(context, stats, shortString);
if (shouldCloseBatteryUsageStats) {
try {
stats.close();
@@ -196,23 +213,22 @@ public class BatteryInfo {
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
/**
* Creates a BatteryInfo based on BatteryUsageStats
*/
/** Creates a BatteryInfo based on BatteryUsageStats */
@WorkerThread
public static BatteryInfo getBatteryInfo(final Context context,
@NonNull final BatteryUsageStats batteryUsageStats, boolean shortString) {
public static BatteryInfo getBatteryInfo(
final Context context,
@NonNull final BatteryUsageStats batteryUsageStats,
boolean shortString) {
final long batteryStatsTime = System.currentTimeMillis();
BatteryUtils.logRuntime(LOG_TAG, "time for getStats", batteryStatsTime);
final long startTime = System.currentTimeMillis();
PowerUsageFeatureProvider provider =
FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider();
final long elapsedRealtimeUs =
PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());
final long elapsedRealtimeUs = PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());
final Intent batteryBroadcast = context.registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
final Intent batteryBroadcast =
context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
// 0 means we are discharging, anything else means charging
final boolean discharging =
batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) == 0;
@@ -221,40 +237,65 @@ public class BatteryInfo {
Estimate estimate = provider.getEnhancedBatteryPrediction(context);
if (estimate != null) {
Estimate.storeCachedEstimate(context, estimate);
BatteryUtils
.logRuntime(LOG_TAG, "time for enhanced BatteryInfo", startTime);
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, batteryUsageStats,
estimate, elapsedRealtimeUs, shortString);
BatteryUtils.logRuntime(LOG_TAG, "time for enhanced BatteryInfo", startTime);
return BatteryInfo.getBatteryInfo(
context,
batteryBroadcast,
batteryUsageStats,
estimate,
elapsedRealtimeUs,
shortString);
}
}
final long prediction = discharging ? batteryUsageStats.getBatteryTimeRemainingMs() : 0;
final Estimate estimate = new Estimate(
prediction,
false, /* isBasedOnUsage */
EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
final Estimate estimate =
new Estimate(
prediction,
false, /* isBasedOnUsage */
EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
BatteryUtils.logRuntime(LOG_TAG, "time for regular BatteryInfo", startTime);
return BatteryInfo.getBatteryInfo(context, batteryBroadcast, batteryUsageStats,
estimate, elapsedRealtimeUs, shortString);
return BatteryInfo.getBatteryInfo(
context,
batteryBroadcast,
batteryUsageStats,
estimate,
elapsedRealtimeUs,
shortString);
}
@WorkerThread
public static BatteryInfo getBatteryInfoOld(Context context, Intent batteryBroadcast,
BatteryUsageStats batteryUsageStats, long elapsedRealtimeUs, boolean shortString) {
Estimate estimate = new Estimate(
batteryUsageStats.getBatteryTimeRemainingMs(),
false,
EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
return getBatteryInfo(context, batteryBroadcast, batteryUsageStats, estimate,
elapsedRealtimeUs, shortString);
public static BatteryInfo getBatteryInfoOld(
Context context,
Intent batteryBroadcast,
BatteryUsageStats batteryUsageStats,
long elapsedRealtimeUs,
boolean shortString) {
Estimate estimate =
new Estimate(
batteryUsageStats.getBatteryTimeRemainingMs(),
false,
EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
return getBatteryInfo(
context,
batteryBroadcast,
batteryUsageStats,
estimate,
elapsedRealtimeUs,
shortString);
}
@WorkerThread
public static BatteryInfo getBatteryInfo(Context context, Intent batteryBroadcast,
@NonNull BatteryUsageStats batteryUsageStats, Estimate estimate,
long elapsedRealtimeUs, boolean shortString) {
public static BatteryInfo getBatteryInfo(
Context context,
Intent batteryBroadcast,
@NonNull BatteryUsageStats batteryUsageStats,
Estimate estimate,
long elapsedRealtimeUs,
boolean shortString) {
final long startTime = System.currentTimeMillis();
final boolean isCompactStatus = context.getResources().getBoolean(
com.android.settings.R.bool.config_use_compact_battery_status);
final boolean isCompactStatus =
context.getResources()
.getBoolean(com.android.settings.R.bool.config_use_compact_battery_status);
BatteryInfo info = new BatteryInfo();
info.mBatteryUsageStats = batteryUsageStats;
info.batteryLevel = Utils.getBatteryLevel(batteryBroadcast);
@@ -262,25 +303,32 @@ public class BatteryInfo {
info.pluggedStatus = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
info.mCharging = info.pluggedStatus != 0;
info.averageTimeToDischarge = estimate.getAverageDischargeTime();
info.isBatteryDefender = batteryBroadcast.getIntExtra(
BatteryManager.EXTRA_CHARGING_STATUS, BatteryManager.CHARGING_POLICY_DEFAULT)
== BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE;
info.isBatteryDefender =
batteryBroadcast.getIntExtra(
BatteryManager.EXTRA_CHARGING_STATUS,
BatteryManager.CHARGING_POLICY_DEFAULT)
== BatteryManager.CHARGING_POLICY_ADAPTIVE_LONGLIFE;
info.statusLabel = Utils.getBatteryStatus(context, batteryBroadcast, isCompactStatus);
info.batteryStatus = batteryBroadcast.getIntExtra(
BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN);
info.batteryStatus =
batteryBroadcast.getIntExtra(
BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN);
if (!info.mCharging) {
updateBatteryInfoDischarging(context, shortString, estimate, info);
} else {
updateBatteryInfoCharging(context, batteryBroadcast, batteryUsageStats,
info, isCompactStatus);
updateBatteryInfoCharging(
context, batteryBroadcast, batteryUsageStats, info, isCompactStatus);
}
BatteryUtils.logRuntime(LOG_TAG, "time for getBatteryInfo", startTime);
return info;
}
private static void updateBatteryInfoCharging(Context context, Intent batteryBroadcast,
BatteryUsageStats stats, BatteryInfo info, boolean compactStatus) {
private static void updateBatteryInfoCharging(
Context context,
Intent batteryBroadcast,
BatteryUsageStats stats,
BatteryInfo info,
boolean compactStatus) {
final Resources resources = context.getResources();
final long chargeTimeMs = stats.getChargeTimeRemainingMs();
if (getSettingsChargeTimeRemaining(context) != chargeTimeMs) {
@@ -290,59 +338,76 @@ public class BatteryInfo {
chargeTimeMs);
}
final int status = batteryBroadcast.getIntExtra(BatteryManager.EXTRA_STATUS,
BatteryManager.BATTERY_STATUS_UNKNOWN);
final int status =
batteryBroadcast.getIntExtra(
BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_STATUS_UNKNOWN);
info.discharging = false;
info.suggestionLabel = null;
int dockDefenderMode = BatteryUtils.getCurrentDockDefenderMode(context, info);
if ((info.isBatteryDefender && status != BatteryManager.BATTERY_STATUS_FULL
&& dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
if ((info.isBatteryDefender
&& status != BatteryManager.BATTERY_STATUS_FULL
&& dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
|| dockDefenderMode == BatteryUtils.DockDefenderMode.ACTIVE) {
// Battery defender active, battery charging paused
info.remainingLabel = null;
int chargingLimitedResId = com.android.settingslib.R.string.power_charging_limited;
info.chargeLabel = context.getString(chargingLimitedResId, info.batteryPercentString);
} else if ((chargeTimeMs > 0 && status != BatteryManager.BATTERY_STATUS_FULL
&& dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
} else if ((chargeTimeMs > 0
&& status != BatteryManager.BATTERY_STATUS_FULL
&& dockDefenderMode == BatteryUtils.DockDefenderMode.DISABLED)
|| dockDefenderMode == BatteryUtils.DockDefenderMode.TEMPORARILY_BYPASSED) {
// Battery is charging to full
info.remainingTimeUs = PowerUtil.convertMsToUs(chargeTimeMs);
final CharSequence timeString = StringUtil.formatElapsedTime(context,
(double) PowerUtil.convertUsToMs(info.remainingTimeUs), false /* withSeconds */,
true /* collapseTimeUnit */);
final CharSequence timeString =
StringUtil.formatElapsedTime(
context,
(double) PowerUtil.convertUsToMs(info.remainingTimeUs),
false /* withSeconds */,
true /* collapseTimeUnit */);
int resId = com.android.settingslib.R.string.power_charging_duration;
info.remainingLabel = chargeTimeMs <= 0 ? null : context.getString(
com.android.settingslib.R.string.power_remaining_charging_duration_only,
timeString);
info.chargeLabel = chargeTimeMs <= 0 ? info.batteryPercentString
: context.getString(resId, info.batteryPercentString, timeString);
info.remainingLabel =
chargeTimeMs <= 0
? null
: context.getString(
com.android.settingslib.R.string
.power_remaining_charging_duration_only,
timeString);
info.chargeLabel =
chargeTimeMs <= 0
? info.batteryPercentString
: context.getString(resId, info.batteryPercentString, timeString);
} else if (dockDefenderMode == BatteryUtils.DockDefenderMode.FUTURE_BYPASS) {
// Dock defender will be triggered in the future, charging will be optimized.
info.chargeLabel = context.getString(
com.android.settingslib.R.string.power_charging_future_paused,
info.batteryPercentString);
info.chargeLabel =
context.getString(
com.android.settingslib.R.string.power_charging_future_paused,
info.batteryPercentString);
} else {
final String chargeStatusLabel = Utils.getBatteryStatus(context, batteryBroadcast,
compactStatus);
final String chargeStatusLabel =
Utils.getBatteryStatus(context, batteryBroadcast, compactStatus);
info.remainingLabel = null;
info.chargeLabel = info.batteryLevel == 100 ? info.batteryPercentString :
resources.getString(com.android.settingslib.R.string.power_charging,
info.batteryPercentString, chargeStatusLabel);
info.chargeLabel =
info.batteryLevel == 100
? info.batteryPercentString
: resources.getString(
com.android.settingslib.R.string.power_charging,
info.batteryPercentString,
chargeStatusLabel);
}
}
private static void updateBatteryInfoDischarging(Context context, boolean shortString,
Estimate estimate, BatteryInfo info) {
private static void updateBatteryInfoDischarging(
Context context, boolean shortString, Estimate estimate, BatteryInfo info) {
final long drainTimeUs = PowerUtil.convertMsToUs(estimate.getEstimateMillis());
if (drainTimeUs > 0) {
info.remainingTimeUs = drainTimeUs;
info.remainingLabel = PowerUtil.getBatteryRemainingShortStringFormatted(
context,
PowerUtil.convertUsToMs(drainTimeUs)
);
info.remainingLabel =
PowerUtil.getBatteryRemainingShortStringFormatted(
context, PowerUtil.convertUsToMs(drainTimeUs));
info.chargeLabel = info.remainingLabel;
info.suggestionLabel = PowerUtil.getBatteryTipStringFormatted(
context, PowerUtil.convertUsToMs(drainTimeUs));
info.suggestionLabel =
PowerUtil.getBatteryTipStringFormatted(
context, PowerUtil.convertUsToMs(drainTimeUs));
} else {
info.remainingLabel = null;
info.suggestionLabel = null;
@@ -361,8 +426,8 @@ public class BatteryInfo {
}
/**
* Iterates over battery history included in the BatteryUsageStats that this object
* was initialized with.
* Iterates over battery history included in the BatteryUsageStats that this object was
* initialized with.
*/
public void parseBatteryHistory(BatteryDataParser... parsers) {
long startWalltime = 0;
@@ -384,8 +449,7 @@ public class BatteryInfo {
first = false;
historyStart = rec.time;
}
if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
|| rec.cmd == HistoryItem.CMD_RESET) {
if (rec.cmd == HistoryItem.CMD_CURRENT_TIME || rec.cmd == HistoryItem.CMD_RESET) {
// If there is a ridiculously large jump in time, then we won't be
// able to create a good chart with that data, so just ignore the
// times we got before and pretend like our data extends back from
@@ -447,7 +511,7 @@ public class BatteryInfo {
if (rec.cmd != HistoryItem.CMD_OVERFLOW
&& (rec.cmd != HistoryItem.CMD_CURRENT_TIME
|| Math.abs(lastWalltime - curWalltime) > (60 * 60 * 1000))) {
|| Math.abs(lastWalltime - curWalltime) > (60 * 60 * 1000))) {
for (int j = 0; j < parsers.length; j++) {
parsers[j].onDataGap();
}

View File

@@ -26,11 +26,10 @@ import com.android.settingslib.utils.AsyncLoaderCompat;
* automatically grab enhanced battery estimates if available or fall back to the system estimate
* when not available.
*/
public class BatteryInfoLoader extends AsyncLoaderCompat<BatteryInfo>{
public class BatteryInfoLoader extends AsyncLoaderCompat<BatteryInfo> {
private static final String LOG_TAG = "BatteryInfoLoader";
@VisibleForTesting
BatteryUtils mBatteryUtils;
@VisibleForTesting BatteryUtils mBatteryUtils;
public BatteryInfoLoader(Context context) {
super(context);
@@ -38,9 +37,7 @@ public class BatteryInfoLoader extends AsyncLoaderCompat<BatteryInfo>{
}
@Override
protected void onDiscardResult(BatteryInfo result) {
}
protected void onDiscardResult(BatteryInfo result) {}
@Override
public BatteryInfo loadInBackground() {

View File

@@ -29,14 +29,10 @@ import com.android.settings.Utils;
import com.android.settingslib.graph.ThemedBatteryDrawable;
public class BatteryMeterView extends ImageView {
@VisibleForTesting
BatteryMeterDrawable mDrawable;
@VisibleForTesting
ColorFilter mErrorColorFilter;
@VisibleForTesting
ColorFilter mAccentColorFilter;
@VisibleForTesting
ColorFilter mForegroundColorFilter;
@VisibleForTesting BatteryMeterDrawable mDrawable;
@VisibleForTesting ColorFilter mErrorColorFilter;
@VisibleForTesting ColorFilter mAccentColorFilter;
@VisibleForTesting ColorFilter mForegroundColorFilter;
public BatteryMeterView(Context context) {
this(context, null, 0);
@@ -51,12 +47,15 @@ public class BatteryMeterView extends ImageView {
final int frameColor =
context.getColor(com.android.settingslib.R.color.meter_background_color);
mAccentColorFilter = Utils.getAlphaInvariantColorFilterForColor(
Utils.getColorAttrDefaultColor(context, android.R.attr.colorAccent));
mErrorColorFilter = Utils.getAlphaInvariantColorFilterForColor(
context.getColor(R.color.battery_icon_color_error));
mForegroundColorFilter = Utils.getAlphaInvariantColorFilterForColor(
Utils.getColorAttrDefaultColor(context, android.R.attr.colorForeground));
mAccentColorFilter =
Utils.getAlphaInvariantColorFilterForColor(
Utils.getColorAttrDefaultColor(context, android.R.attr.colorAccent));
mErrorColorFilter =
Utils.getAlphaInvariantColorFilterForColor(
context.getColor(R.color.battery_icon_color_error));
mForegroundColorFilter =
Utils.getAlphaInvariantColorFilterForColor(
Utils.getColorAttrDefaultColor(context, android.R.attr.colorForeground));
mDrawable = new BatteryMeterDrawable(context, frameColor);
mDrawable.setColorFilter(mAccentColorFilter);
setImageDrawable(mDrawable);
@@ -108,10 +107,10 @@ public class BatteryMeterView extends ImageView {
public BatteryMeterDrawable(Context context, int frameColor) {
super(context, frameColor);
mIntrinsicWidth = context.getResources()
.getDimensionPixelSize(R.dimen.battery_meter_width);
mIntrinsicHeight = context.getResources()
.getDimensionPixelSize(R.dimen.battery_meter_height);
mIntrinsicWidth =
context.getResources().getDimensionPixelSize(R.dimen.battery_meter_width);
mIntrinsicHeight =
context.getResources().getDimensionPixelSize(R.dimen.battery_meter_height);
}
public BatteryMeterDrawable(Context context, int frameColor, int width, int height) {

View File

@@ -34,8 +34,7 @@ public final class BatteryOptimizeLogUtils {
private static final String BATTERY_OPTIMIZE_FILE_NAME = "battery_optimize_historical_logs";
private static final String LOGS_KEY = "battery_optimize_logs_key";
@VisibleForTesting
static final int MAX_ENTRIES = 40;
@VisibleForTesting static final int MAX_ENTRIES = 40;
private BatteryOptimizeLogUtils() {}
@@ -45,8 +44,11 @@ public final class BatteryOptimizeLogUtils {
writeLog(getSharedPreferences(context), action, packageName, actionDescription);
}
static void writeLog(SharedPreferences sharedPreferences, Action action,
String packageName, String actionDescription) {
static void writeLog(
SharedPreferences sharedPreferences,
Action action,
String packageName,
String actionDescription) {
writeLog(
sharedPreferences,
BatteryOptimizeHistoricalLogEntry.newBuilder()
@@ -70,10 +72,7 @@ public final class BatteryOptimizeLogUtils {
String loggingContent =
Base64.encodeToString(newLogBuilder.build().toByteArray(), Base64.DEFAULT);
sharedPreferences
.edit()
.putString(LOGS_KEY, loggingContent)
.apply();
sharedPreferences.edit().putString(LOGS_KEY, loggingContent).apply();
}
private static BatteryOptimizeHistoricalLog parseLogFromString(String storedLogs) {
@@ -107,9 +106,11 @@ public final class BatteryOptimizeLogUtils {
}
private static String toString(BatteryOptimizeHistoricalLogEntry entry) {
return String.format("%s\t%s\taction:%s\tevent:%s",
return String.format(
"%s\t%s\taction:%s\tevent:%s",
ConvertUtils.utcToLocalTimeForLogging(entry.getTimestamp()),
entry.getPackageName(), entry.getAction(),
entry.getPackageName(),
entry.getAction(),
entry.getActionDescription());
}

View File

@@ -62,11 +62,11 @@ public class BatteryOptimizeUtils {
// If current user is admin, match apps from all users. Otherwise, only match the currect user.
private static final int RETRIEVE_FLAG_ADMIN =
PackageManager.MATCH_ANY_USER
| PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
| PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
private static final int RETRIEVE_FLAG =
PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
| PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
// Optimization modes.
static final int MODE_UNKNOWN = 0;
@@ -74,12 +74,14 @@ public class BatteryOptimizeUtils {
static final int MODE_UNRESTRICTED = 2;
static final int MODE_OPTIMIZED = 3;
@IntDef(prefix = {"MODE_"}, value = {
MODE_UNKNOWN,
MODE_RESTRICTED,
MODE_UNRESTRICTED,
MODE_OPTIMIZED,
})
@IntDef(
prefix = {"MODE_"},
value = {
MODE_UNKNOWN,
MODE_RESTRICTED,
MODE_UNRESTRICTED,
MODE_OPTIMIZED,
})
@Retention(RetentionPolicy.SOURCE)
static @interface OptimizationMode {}
@@ -118,8 +120,12 @@ public class BatteryOptimizeUtils {
/** Resets optimization mode for all applications. */
public static void resetAppOptimizationMode(
Context context, IPackageManager ipm, AppOpsManager aom) {
resetAppOptimizationMode(context, ipm, aom,
PowerAllowlistBackend.getInstance(context), BatteryUtils.getInstance(context));
resetAppOptimizationMode(
context,
ipm,
aom,
PowerAllowlistBackend.getInstance(context),
BatteryUtils.getInstance(context));
}
/** Sets the {@link OptimizationMode} for associated app. */
@@ -138,17 +144,13 @@ public class BatteryOptimizeUtils {
|| mBatteryUtils.getPackageUid(mPackageName) == BatteryUtils.UID_NULL;
}
/**
* Return {@code true} if this package is system or default active app.
*/
/** Return {@code true} if this package is system or default active app. */
public boolean isSystemOrDefaultApp() {
mPowerAllowListBackend.refreshList();
return isSystemOrDefaultApp(mContext, mPowerAllowListBackend, mPackageName, mUid);
}
/**
* Return {@code true} if the optimization mode of this package can be changed
*/
/** Return {@code true} if the optimization mode of this package can be changed */
public boolean isOptimizeModeMutable() {
return !isDisabledForOptimizeModeOnly() && !isSystemOrDefaultApp();
}
@@ -162,9 +164,7 @@ public class BatteryOptimizeUtils {
&& getAppOptimizationMode() != BatteryOptimizeUtils.MODE_RESTRICTED;
}
/**
* Gets the list of installed applications.
*/
/** Gets the list of installed applications. */
public static ArraySet<ApplicationInfo> getInstalledApplications(
Context context, IPackageManager ipm) {
final ArraySet<ApplicationInfo> applications = new ArraySet<>();
@@ -172,9 +172,10 @@ public class BatteryOptimizeUtils {
for (UserInfo userInfo : um.getProfiles(UserHandle.myUserId())) {
try {
@SuppressWarnings("unchecked")
final ParceledListSlice<ApplicationInfo> infoList = ipm.getInstalledApplications(
userInfo.isAdmin() ? RETRIEVE_FLAG_ADMIN : RETRIEVE_FLAG,
userInfo.id);
final ParceledListSlice<ApplicationInfo> infoList =
ipm.getInstalledApplications(
userInfo.isAdmin() ? RETRIEVE_FLAG_ADMIN : RETRIEVE_FLAG,
userInfo.id);
if (infoList != null) {
applications.addAll(infoList.getList());
}
@@ -185,15 +186,19 @@ public class BatteryOptimizeUtils {
}
// Removes the application which is disabled by the system.
applications.removeIf(
info -> info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER
&& !info.enabled);
info ->
info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER
&& !info.enabled);
return applications;
}
@VisibleForTesting
static void resetAppOptimizationMode(
Context context, IPackageManager ipm, AppOpsManager aom,
PowerAllowlistBackend allowlistBackend, BatteryUtils batteryUtils) {
Context context,
IPackageManager ipm,
AppOpsManager aom,
PowerAllowlistBackend allowlistBackend,
BatteryUtils batteryUtils) {
final ArraySet<ApplicationInfo> applications = getInstalledApplications(context, ipm);
if (applications == null || applications.isEmpty()) {
Log.w(TAG, "no data found in the getInstalledApplications()");
@@ -203,11 +208,13 @@ public class BatteryOptimizeUtils {
allowlistBackend.refreshList();
// Resets optimization mode for each application.
for (ApplicationInfo info : applications) {
final int mode = aom.checkOpNoThrow(
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, info.uid, info.packageName);
final int mode =
aom.checkOpNoThrow(
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, info.uid, info.packageName);
@OptimizationMode
final int optimizationMode = getAppOptimizationMode(
mode, allowlistBackend.isAllowlisted(info.packageName, info.uid));
final int optimizationMode =
getAppOptimizationMode(
mode, allowlistBackend.isAllowlisted(info.packageName, info.uid));
// Ignores default optimized/unknown state or system/default apps.
if (optimizationMode == MODE_OPTIMIZED
|| optimizationMode == MODE_UNKNOWN
@@ -217,8 +224,14 @@ public class BatteryOptimizeUtils {
}
// Resets to the default mode: MODE_OPTIMIZED.
setAppUsageStateInternal(context, MODE_OPTIMIZED, info.uid, info.packageName,
batteryUtils, allowlistBackend, Action.RESET);
setAppUsageStateInternal(
context,
MODE_OPTIMIZED,
info.uid,
info.packageName,
batteryUtils,
allowlistBackend,
Action.RESET);
}
}
@@ -244,25 +257,33 @@ public class BatteryOptimizeUtils {
static List<String> getForceBatteryOptimizeModeList(Context context) {
if (sBatteryOptimizeModeList == null) {
sBatteryOptimizeModeList = Arrays.asList(
context.getResources().getStringArray(
R.array.config_force_battery_optimize_mode_apps));
sBatteryOptimizeModeList =
Arrays.asList(
context.getResources()
.getStringArray(
R.array.config_force_battery_optimize_mode_apps));
}
return sBatteryOptimizeModeList;
}
static List<String> getForceBatteryUnrestrictModeList(Context context) {
if (sBatteryUnrestrictModeList == null) {
sBatteryUnrestrictModeList = Arrays.asList(
context.getResources().getStringArray(
R.array.config_force_battery_unrestrict_mode_apps));
sBatteryUnrestrictModeList =
Arrays.asList(
context.getResources()
.getStringArray(
R.array.config_force_battery_unrestrict_mode_apps));
}
return sBatteryUnrestrictModeList;
}
private static void setAppUsageStateInternal(
Context context, @OptimizationMode int mode, int uid, String packageName,
BatteryUtils batteryUtils, PowerAllowlistBackend powerAllowlistBackend,
Context context,
@OptimizationMode int mode,
int uid,
String packageName,
BatteryUtils batteryUtils,
PowerAllowlistBackend powerAllowlistBackend,
Action action) {
if (mode == MODE_UNKNOWN) {
Log.d(TAG, "set unknown app optimization mode.");
@@ -276,16 +297,29 @@ public class BatteryOptimizeUtils {
mode == MODE_RESTRICTED ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED;
final boolean allowListed = mode == MODE_UNRESTRICTED;
setAppOptimizationModeInternal(context, appOpsManagerMode, allowListed, uid,
packageName, batteryUtils, powerAllowlistBackend, action);
setAppOptimizationModeInternal(
context,
appOpsManagerMode,
allowListed,
uid,
packageName,
batteryUtils,
powerAllowlistBackend,
action);
}
private static void setAppOptimizationModeInternal(
Context context, int appStandbyMode, boolean allowListed, int uid, String packageName,
BatteryUtils batteryUtils, PowerAllowlistBackend powerAllowlistBackend,
Context context,
int appStandbyMode,
boolean allowListed,
int uid,
String packageName,
BatteryUtils batteryUtils,
PowerAllowlistBackend powerAllowlistBackend,
Action action) {
final String packageNameKey = BatteryOptimizeLogUtils
.getPackageNameWithUserId(packageName, UserHandle.myUserId());
final String packageNameKey =
BatteryOptimizeLogUtils.getPackageNameWithUserId(
packageName, UserHandle.myUserId());
try {
batteryUtils.setForceAppStandby(uid, packageName, appStandbyMode);
if (allowListed) {
@@ -299,24 +333,27 @@ public class BatteryOptimizeUtils {
Log.e(TAG, "set OPTIMIZATION MODE failed for " + packageName, e);
}
BatteryOptimizeLogUtils.writeLog(
context,
action,
packageNameKey,
createLogEvent(appStandbyMode, allowListed));
context, action, packageNameKey, createLogEvent(appStandbyMode, allowListed));
}
private void refreshState() {
mPowerAllowListBackend.refreshList();
mAllowListed = mPowerAllowListBackend.isAllowlisted(mPackageName, mUid);
mMode = mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mPackageName);
Log.d(TAG, String.format("refresh %s state, allowlisted = %s, mode = %d",
mPackageName, mAllowListed, mMode));
mMode =
mAppOpsManager.checkOpNoThrow(
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, mUid, mPackageName);
Log.d(
TAG,
String.format(
"refresh %s state, allowlisted = %s, mode = %d",
mPackageName, mAllowListed, mMode));
}
private static String createLogEvent(int appStandbyMode, boolean allowListed) {
return appStandbyMode < 0 ? "Apply optimize setting ERROR" :
String.format("\tStandbyMode: %s, allowListed: %s, mode: %s",
return appStandbyMode < 0
? "Apply optimize setting ERROR"
: String.format(
"\tStandbyMode: %s, allowListed: %s, mode: %s",
appStandbyMode,
allowListed,
getAppOptimizationMode(appStandbyMode, allowListed));

View File

@@ -16,15 +16,12 @@
package com.android.settings.fuelgauge;
/**
* Common interface for a preference controller that updates battery status
*/
/** Common interface for a preference controller that updates battery status */
public interface BatteryPreferenceController {
/**
* Updates the label for the preference controller. If the label is null, the
* implementation should revert back to the original label based on the
* battery info.
* Updates the label for the preference controller. If the label is null, the implementation
* should revert back to the original label based on the battery info.
*/
void updateBatteryStatus(String label, BatteryInfo info);
}

View File

@@ -35,22 +35,20 @@ import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.fuelgauge.BatterySaverUtils;
/**
* Controller to update the battery saver entry preference.
*/
/** Controller to update the battery saver entry preference. */
public class BatterySaverController extends BasePreferenceController
implements LifecycleObserver, OnStart, OnStop, BatterySaverReceiver.BatterySaverListener {
private static final String KEY_BATTERY_SAVER = "battery_saver_summary";
private final BatterySaverReceiver mBatteryStateChangeReceiver;
private final PowerManager mPowerManager;
private Preference mBatterySaverPref;
private final ContentObserver mObserver = new ContentObserver(
new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange) {
updateSummary();
}
};
private final ContentObserver mObserver =
new ContentObserver(new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange) {
updateSummary();
}
};
public BatterySaverController(Context context) {
super(context, KEY_BATTERY_SAVER);
@@ -79,9 +77,11 @@ public class BatterySaverController extends BasePreferenceController
@Override
public void onStart() {
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
true /* notifyForDescendants */, mObserver);
mContext.getContentResolver()
.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
true /* notifyForDescendants */,
mObserver);
mBatteryStateChangeReceiver.setListening(true);
updateSummary();
@@ -101,15 +101,20 @@ public class BatterySaverController extends BasePreferenceController
}
final ContentResolver resolver = mContext.getContentResolver();
final int mode = Settings.Global.getInt(resolver,
Global.AUTOMATIC_POWER_SAVE_MODE, PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
final int mode =
Settings.Global.getInt(
resolver,
Global.AUTOMATIC_POWER_SAVE_MODE,
PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
if (mode == PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE) {
final int percent = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
return percent != 0 ?
mContext.getString(R.string.battery_saver_off_scheduled_summary,
Utils.formatPercentage(percent)) :
mContext.getString(R.string.battery_saver_off_summary);
final int percent =
Settings.Global.getInt(
resolver, Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
return percent != 0
? mContext.getString(
R.string.battery_saver_off_scheduled_summary,
Utils.formatPercentage(percent))
: mContext.getString(R.string.battery_saver_off_summary);
} else {
return mContext.getString(R.string.battery_saver_pref_auto_routine_summary);
}
@@ -127,6 +132,5 @@ public class BatterySaverController extends BasePreferenceController
}
@Override
public void onBatteryChanged(boolean pluggedIn) {
}
public void onBatteryChanged(boolean pluggedIn) {}
}

View File

@@ -23,9 +23,7 @@ import android.graphics.PorterDuffColorFilter;
import com.android.settingslib.Utils;
import com.android.settingslib.graph.BatteryMeterDrawableBase;
/**
* Drawable that shows a static battery saver icon - a full battery symbol and a plus sign.
*/
/** Drawable that shows a static battery saver icon - a full battery symbol and a plus sign. */
public class BatterySaverDrawable extends BatteryMeterDrawableBase {
private static final int MAX_BATTERY = 100;

View File

@@ -27,8 +27,8 @@ import com.android.settings.utils.VoiceSettingsActivity;
import com.android.settingslib.fuelgauge.BatterySaverUtils;
/**
* Activity for modifying the {@link android.os.PowerManager} power save mode
* setting using the Voice Interaction API.
* Activity for modifying the {@link android.os.PowerManager} power save mode setting using the
* Voice Interaction API.
*/
public class BatterySaverModeVoiceActivity extends VoiceSettingsActivity {
private static final String TAG = "BatterySaverModeVoiceActivity";
@@ -36,9 +36,11 @@ public class BatterySaverModeVoiceActivity extends VoiceSettingsActivity {
@Override
protected boolean onVoiceSettingInteraction(Intent intent) {
if (intent.hasExtra(EXTRA_BATTERY_SAVER_MODE_ENABLED)) {
if (BatterySaverUtils.setPowerSaveMode(this,
if (BatterySaverUtils.setPowerSaveMode(
this,
intent.getBooleanExtra(EXTRA_BATTERY_SAVER_MODE_ENABLED, false),
/*needFirstTimeWarning=*/ true, SAVER_ENABLED_VOICE)) {
/* needFirstTimeWarning= */ true,
SAVER_ENABLED_VOICE)) {
notifySuccess(null);
} else {
Log.v(TAG, "Unable to set power mode");

View File

@@ -71,6 +71,7 @@ public class BatterySaverReceiver extends BroadcastReceiver {
public interface BatterySaverListener {
void onPowerSaveModeChanged();
void onBatteryChanged(boolean pluggedIn);
}
}

View File

@@ -34,8 +34,7 @@ import java.util.List;
public final class BatterySettingsMigrateChecker extends BroadcastReceiver {
private static final String TAG = "BatterySettingsMigrateChecker";
@VisibleForTesting
static BatteryOptimizeUtils sBatteryOptimizeUtils = null;
@VisibleForTesting static BatteryOptimizeUtils sBatteryOptimizeUtils = null;
@Override
public void onReceive(Context context, Intent intent) {
@@ -71,31 +70,38 @@ public final class BatterySettingsMigrateChecker extends BroadcastReceiver {
Context context,
@BatteryOptimizeUtils.OptimizationMode int optimizationMode,
List<String> allowList) {
allowList.forEach(packageName -> {
final BatteryOptimizeUtils batteryOptimizeUtils =
BatteryBackupHelper.newBatteryOptimizeUtils(context, packageName,
/* testOptimizeUtils */ sBatteryOptimizeUtils);
if (batteryOptimizeUtils == null) {
return;
}
if (batteryOptimizeUtils.getAppOptimizationMode() != optimizationMode) {
Log.w(TAG, "Reset " + packageName + " battery mode into " + optimizationMode);
batteryOptimizeUtils.setAppUsageState(
optimizationMode,
BatteryOptimizeHistoricalLogEntry.Action.FORCE_RESET);
}
});
allowList.forEach(
packageName -> {
final BatteryOptimizeUtils batteryOptimizeUtils =
BatteryBackupHelper.newBatteryOptimizeUtils(
context,
packageName,
/* testOptimizeUtils */ sBatteryOptimizeUtils);
if (batteryOptimizeUtils == null) {
return;
}
if (batteryOptimizeUtils.getAppOptimizationMode() != optimizationMode) {
Log.w(
TAG,
"Reset " + packageName + " battery mode into " + optimizationMode);
batteryOptimizeUtils.setAppUsageState(
optimizationMode,
BatteryOptimizeHistoricalLogEntry.Action.FORCE_RESET);
}
});
}
static void verifySaverConfiguration(Context context) {
Log.d(TAG, "invoke verifySaverConfiguration()");
final ContentResolver resolver = context.getContentResolver();
final int threshold = Settings.Global.getInt(resolver,
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
final int threshold =
Settings.Global.getInt(resolver, Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
// Force refine the invalid scheduled battery level.
if (threshold < BatterySaverScheduleRadioButtonsController.TRIGGER_LEVEL_MIN
&& threshold > 0) {
Settings.Global.putInt(resolver, Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL,
Settings.Global.putInt(
resolver,
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL,
BatterySaverScheduleRadioButtonsController.TRIGGER_LEVEL_MIN);
Log.w(TAG, "Reset invalid scheduled battery level from: " + threshold);
}

View File

@@ -16,14 +16,9 @@
package com.android.settings.fuelgauge;
/**
* Feature Provider used to retrieve battery status
*/
/** Feature Provider used to retrieve battery status */
public interface BatteryStatusFeatureProvider {
/**
* Trigger a battery status update; return false if built-in status should be used.
*/
boolean triggerBatteryStatusUpdate(
BatteryPreferenceController controller, BatteryInfo info);
/** Trigger a battery status update; return false if built-in status should be used. */
boolean triggerBatteryStatusUpdate(BatteryPreferenceController controller, BatteryInfo info);
}

View File

@@ -18,9 +18,7 @@ package com.android.settings.fuelgauge;
import android.content.Context;
/**
* Used to override battery status string in Battery Header.
*/
/** Used to override battery status string in Battery Header. */
public class BatteryStatusFeatureProviderImpl implements BatteryStatusFeatureProvider {
protected Context mContext;

View File

@@ -70,15 +70,15 @@ import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.List;
/**
* Utils for battery operation
*/
/** Utils for battery operation */
public class BatteryUtils {
public static final int UID_ZERO = 0;
public static final int UID_NULL = -1;
public static final int SDK_NULL = -1;
/** Special UID value for data usage by removed apps. */
public static final int UID_REMOVED_APPS = -4;
/** Special UID value for data usage by tethering. */
public static final int UID_TETHERING = -5;
@@ -91,11 +91,7 @@ public class BatteryUtils {
private static final String PACKAGE_NAME_NONE = "none";
@Retention(RetentionPolicy.SOURCE)
@IntDef({StatusType.SCREEN_USAGE,
StatusType.FOREGROUND,
StatusType.BACKGROUND,
StatusType.ALL
})
@IntDef({StatusType.SCREEN_USAGE, StatusType.FOREGROUND, StatusType.BACKGROUND, StatusType.ALL})
public @interface StatusType {
int SCREEN_USAGE = 0;
int FOREGROUND = 1;
@@ -104,10 +100,12 @@ public class BatteryUtils {
}
@Retention(RetentionPolicy.SOURCE)
@IntDef({DockDefenderMode.FUTURE_BYPASS,
DockDefenderMode.ACTIVE,
DockDefenderMode.TEMPORARILY_BYPASSED,
DockDefenderMode.DISABLED})
@IntDef({
DockDefenderMode.FUTURE_BYPASS,
DockDefenderMode.ACTIVE,
DockDefenderMode.TEMPORARILY_BYPASSED,
DockDefenderMode.DISABLED
})
public @interface DockDefenderMode {
int FUTURE_BYPASS = 0;
int ACTIVE = 1;
@@ -122,8 +120,7 @@ public class BatteryUtils {
private AppOpsManager mAppOpsManager;
private Context mContext;
@VisibleForTesting
PowerUsageFeatureProvider mPowerUsageFeatureProvider;
@VisibleForTesting PowerUsageFeatureProvider mPowerUsageFeatureProvider;
public static BatteryUtils getInstance(Context context) {
if (sInstance == null || sInstance.isDataCorrupted()) {
@@ -147,8 +144,9 @@ public class BatteryUtils {
sInstance = null;
}
public long getProcessTimeMs(@StatusType int type, @Nullable BatteryStats.Uid uid,
int which) {
/** Gets the process time */
public long getProcessTimeMs(@StatusType int type, @Nullable BatteryStats.Uid uid, int which) {
if (uid == null) {
return 0;
}
@@ -192,8 +190,9 @@ public class BatteryUtils {
private long getProcessBackgroundTimeMs(BatteryStats.Uid uid, int which) {
final long rawRealTimeUs = PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());
final long timeUs = uid.getProcessStateTime(
BatteryStats.Uid.PROCESS_STATE_BACKGROUND, rawRealTimeUs, which);
final long timeUs =
uid.getProcessStateTime(
BatteryStats.Uid.PROCESS_STATE_BACKGROUND, rawRealTimeUs, which);
Log.v(TAG, "package: " + mPackageManager.getNameForUid(uid.getUid()));
Log.v(TAG, "background time(us): " + timeUs);
@@ -207,17 +206,17 @@ public class BatteryUtils {
}
/**
* Returns true if the specified battery consumer should be excluded from the summary
* battery consumption list.
* Returns true if the specified battery consumer should be excluded from the summary battery
* consumption list.
*/
public boolean shouldHideUidBatteryConsumer(UidBatteryConsumer consumer) {
return shouldHideUidBatteryConsumer(consumer,
mPackageManager.getPackagesForUid(consumer.getUid()));
return shouldHideUidBatteryConsumer(
consumer, mPackageManager.getPackagesForUid(consumer.getUid()));
}
/**
* Returns true if the specified battery consumer should be excluded from the summary
* battery consumption list.
* Returns true if the specified battery consumer should be excluded from the summary battery
* consumption list.
*/
public boolean shouldHideUidBatteryConsumer(UidBatteryConsumer consumer, String[] packages) {
return mPowerUsageFeatureProvider.isTypeSystem(consumer.getUid(), packages)
@@ -225,20 +224,16 @@ public class BatteryUtils {
}
/**
* Returns true if the specified battery consumer should be excluded from
* battery consumption lists, either short or full.
* Returns true if the specified battery consumer should be excluded from battery consumption
* lists, either short or full.
*/
public boolean shouldHideUidBatteryConsumerUnconditionally(UidBatteryConsumer consumer,
String[] packages) {
public boolean shouldHideUidBatteryConsumerUnconditionally(
UidBatteryConsumer consumer, String[] packages) {
final int uid = consumer.getUid();
return uid == UID_TETHERING
? false
: uid < 0 || isHiddenSystemModule(packages);
return uid == UID_TETHERING ? false : uid < 0 || isHiddenSystemModule(packages);
}
/**
* Returns true if one the specified packages belongs to a hidden system module.
*/
/** Returns true if one the specified packages belongs to a hidden system module. */
public boolean isHiddenSystemModule(String[] packages) {
if (packages != null) {
for (int i = 0, length = packages.length; i < length; i++) {
@@ -253,14 +248,14 @@ public class BatteryUtils {
/**
* Calculate the power usage percentage for an app
*
* @param powerUsageMah power used by the app
* @param totalPowerMah total power used in the system
* @param powerUsageMah power used by the app
* @param totalPowerMah total power used in the system
* @param dischargeAmount The discharge amount calculated by {@link BatteryStats}
* @return A percentage value scaled by {@paramref dischargeAmount}
* @see BatteryStats#getDischargeAmount(int)
*/
public double calculateBatteryPercent(double powerUsageMah, double totalPowerMah,
int dischargeAmount) {
public double calculateBatteryPercent(
double powerUsageMah, double totalPowerMah, int dischargeAmount) {
if (totalPowerMah == 0) {
return 0;
}
@@ -272,9 +267,8 @@ public class BatteryUtils {
* Find the package name for a {@link android.os.BatteryStats.Uid}
*
* @param uid id to get the package name
* @return the package name. If there are multiple packages related to
* given id, return the first one. Or return null if there are no known
* packages with the given id
* @return the package name. If there are multiple packages related to given id, return the
* first one. Or return null if there are no known packages with the given id
* @see PackageManager#getPackagesForUid(int)
*/
public String getPackageName(int uid) {
@@ -290,8 +284,8 @@ public class BatteryUtils {
*/
public int getTargetSdkVersion(final String packageName) {
try {
ApplicationInfo info = mPackageManager.getApplicationInfo(packageName,
PackageManager.GET_META_DATA);
ApplicationInfo info =
mPackageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
return info.targetSdkVersion;
} catch (PackageManager.NameNotFoundException e) {
@@ -301,28 +295,26 @@ public class BatteryUtils {
return SDK_NULL;
}
/**
* Check whether background restriction is enabled
*/
public boolean isBackgroundRestrictionEnabled(final int targetSdkVersion, final int uid,
final String packageName) {
/** Check whether background restriction is enabled */
public boolean isBackgroundRestrictionEnabled(
final int targetSdkVersion, final int uid, final String packageName) {
if (targetSdkVersion >= Build.VERSION_CODES.O) {
return true;
}
final int mode = mAppOpsManager
.checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName);
final int mode =
mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_IN_BACKGROUND, uid, packageName);
return mode == AppOpsManager.MODE_IGNORED || mode == AppOpsManager.MODE_ERRORED;
}
/**
* Calculate the time since last full charge, including the device off time
*
* @param batteryUsageStats class that contains the data
* @param currentTimeMs current wall time
* @param batteryUsageStats class that contains the data
* @param currentTimeMs current wall time
* @return time in millis
*/
public long calculateLastFullChargeTime(BatteryUsageStats batteryUsageStats,
long currentTimeMs) {
public long calculateLastFullChargeTime(
BatteryUsageStats batteryUsageStats, long currentTimeMs) {
return currentTimeMs - batteryUsageStats.getStatsStartTimestamp();
}
@@ -330,9 +322,7 @@ public class BatteryUtils {
Log.d(tag, message + ": " + (System.currentTimeMillis() - startTime) + "ms");
}
/**
* Return {@code true} if battery defender is on and charging.
*/
/** Return {@code true} if battery defender is on and charging. */
public static boolean isBatteryDefenderOn(BatteryInfo batteryInfo) {
return batteryInfo.isBatteryDefender && !batteryInfo.discharging;
}
@@ -341,13 +331,14 @@ public class BatteryUtils {
* Find package uid from package name
*
* @param packageName used to find the uid
* @return uid for packageName, or {@link #UID_NULL} if exception happens or
* {@code packageName} is null
* @return uid for packageName, or {@link #UID_NULL} if exception happens or {@code packageName}
* is null
*/
public int getPackageUid(String packageName) {
try {
return packageName == null ? UID_NULL : mPackageManager.getPackageUid(packageName,
PackageManager.GET_META_DATA);
return packageName == null
? UID_NULL
: mPackageManager.getPackageUid(packageName, PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) {
return UID_NULL;
}
@@ -367,16 +358,18 @@ public class BatteryUtils {
return (T) protoClass.getDefaultInstanceForType();
}
try {
return (T) protoClass.getParserForType()
.parseFrom(Base64.decode(serializedProto, Base64.DEFAULT));
return (T)
protoClass
.getParserForType()
.parseFrom(Base64.decode(serializedProto, Base64.DEFAULT));
} catch (InvalidProtocolBufferException e) {
Log.e(TAG, "Failed to deserialize proto class", e);
return (T) protoClass.getDefaultInstanceForType();
}
}
public void setForceAppStandby(int uid, String packageName,
int mode) {
/** Sets force app standby mode */
public void setForceAppStandby(int uid, String packageName, int mode) {
final boolean isPreOApp = isPreOApp(packageName);
if (isPreOApp) {
// Control whether app could run in the background if it is pre O app
@@ -385,22 +378,27 @@ public class BatteryUtils {
// Control whether app could run jobs in the background
mAppOpsManager.setMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName, mode);
ThreadUtils.postOnBackgroundThread(() -> {
final BatteryDatabaseManager batteryDatabaseManager = BatteryDatabaseManager
.getInstance(mContext);
if (mode == AppOpsManager.MODE_IGNORED) {
batteryDatabaseManager.insertAction(AnomalyDatabaseHelper.ActionType.RESTRICTION,
uid, packageName, System.currentTimeMillis());
} else if (mode == AppOpsManager.MODE_ALLOWED) {
batteryDatabaseManager.deleteAction(AnomalyDatabaseHelper.ActionType.RESTRICTION,
uid, packageName);
}
});
ThreadUtils.postOnBackgroundThread(
() -> {
final BatteryDatabaseManager batteryDatabaseManager =
BatteryDatabaseManager.getInstance(mContext);
if (mode == AppOpsManager.MODE_IGNORED) {
batteryDatabaseManager.insertAction(
AnomalyDatabaseHelper.ActionType.RESTRICTION,
uid,
packageName,
System.currentTimeMillis());
} else if (mode == AppOpsManager.MODE_ALLOWED) {
batteryDatabaseManager.deleteAction(
AnomalyDatabaseHelper.ActionType.RESTRICTION, uid, packageName);
}
});
}
public boolean isForceAppStandbyEnabled(int uid, String packageName) {
return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid,
packageName) == AppOpsManager.MODE_IGNORED;
return mAppOpsManager.checkOpNoThrow(
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uid, packageName)
== AppOpsManager.MODE_IGNORED;
}
public boolean clearForceAppStandby(String packageName) {
@@ -415,12 +413,13 @@ public class BatteryUtils {
@WorkerThread
public BatteryInfo getBatteryInfo(final String tag) {
final BatteryStatsManager systemService = mContext.getSystemService(
BatteryStatsManager.class);
final BatteryStatsManager systemService =
mContext.getSystemService(BatteryStatsManager.class);
BatteryUsageStats batteryUsageStats;
try {
batteryUsageStats = systemService.getBatteryUsageStats(
new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build());
batteryUsageStats =
systemService.getBatteryUsageStats(
new BatteryUsageStatsQuery.Builder().includeBatteryHistory().build());
} catch (RuntimeException e) {
Log.e(TAG, "getBatteryInfo() error from getBatteryUsageStats()", e);
// Use default BatteryUsageStats.
@@ -432,23 +431,29 @@ public class BatteryUtils {
// Stuff we always need to get BatteryInfo
final Intent batteryBroadcast = getBatteryIntent(mContext);
final long elapsedRealtimeUs = PowerUtil.convertMsToUs(
SystemClock.elapsedRealtime());
final long elapsedRealtimeUs = PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());
BatteryInfo batteryInfo;
Estimate estimate = getEnhancedEstimate();
// couldn't get estimate from cache or provider, use fallback
if (estimate == null) {
estimate = new Estimate(
batteryUsageStats.getBatteryTimeRemainingMs(),
false /* isBasedOnUsage */,
EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
estimate =
new Estimate(
batteryUsageStats.getBatteryTimeRemainingMs(),
false /* isBasedOnUsage */,
EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
}
BatteryUtils.logRuntime(tag, "BatteryInfoLoader post query", startTime);
batteryInfo = BatteryInfo.getBatteryInfo(mContext, batteryBroadcast,
batteryUsageStats, estimate, elapsedRealtimeUs, false /* shortString */);
batteryInfo =
BatteryInfo.getBatteryInfo(
mContext,
batteryBroadcast,
batteryUsageStats,
estimate,
elapsedRealtimeUs,
false /* shortString */);
BatteryUtils.logRuntime(tag, "BatteryInfoLoader.loadInBackground", startTime);
try {
@@ -463,9 +468,9 @@ public class BatteryUtils {
Estimate getEnhancedEstimate() {
// Align the same logic in the BatteryControllerImpl.updateEstimate()
Estimate estimate = Estimate.getCachedEstimateIfAvailable(mContext);
if (estimate == null &&
mPowerUsageFeatureProvider != null &&
mPowerUsageFeatureProvider.isEnhancedBatteryPredictionEnabled(mContext)) {
if (estimate == null
&& mPowerUsageFeatureProvider != null
&& mPowerUsageFeatureProvider.isEnhancedBatteryPredictionEnabled(mContext)) {
estimate = mPowerUsageFeatureProvider.getEnhancedBatteryPrediction(mContext);
if (estimate != null) {
Estimate.storeCachedEstimate(mContext, estimate);
@@ -500,8 +505,8 @@ public class BatteryUtils {
public boolean isPreOApp(final String packageName) {
try {
ApplicationInfo info = mPackageManager.getApplicationInfo(packageName,
PackageManager.GET_META_DATA);
ApplicationInfo info =
mPackageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
return info.targetSdkVersion < Build.VERSION_CODES.O;
} catch (PackageManager.NameNotFoundException e) {
@@ -525,18 +530,17 @@ public class BatteryUtils {
return false;
}
/**
* Return {@code true} if we should hide anomaly app represented by {@code uid}
*/
public boolean shouldHideAnomaly(PowerAllowlistBackend powerAllowlistBackend, int uid,
AnomalyInfo anomalyInfo) {
/** Return {@code true} if we should hide anomaly app represented by {@code uid} */
public boolean shouldHideAnomaly(
PowerAllowlistBackend powerAllowlistBackend, int uid, AnomalyInfo anomalyInfo) {
final String[] packageNames = mPackageManager.getPackagesForUid(uid);
if (ArrayUtils.isEmpty(packageNames)) {
// Don't show it if app has been uninstalled
return true;
}
return isSystemUid(uid) || powerAllowlistBackend.isAllowlisted(packageNames, uid)
return isSystemUid(uid)
|| powerAllowlistBackend.isAllowlisted(packageNames, uid)
|| (isSystemApp(mPackageManager, packageNames) && !hasLauncherEntry(packageNames))
|| (isExcessiveBackgroundAnomaly(anomalyInfo) && !isPreOApp(packageNames));
}
@@ -554,8 +558,8 @@ public class BatteryUtils {
private boolean isSystemApp(PackageManager packageManager, String[] packageNames) {
for (String packageName : packageNames) {
try {
final ApplicationInfo info = packageManager.getApplicationInfo(packageName,
0 /* flags */);
final ApplicationInfo info =
packageManager.getApplicationInfo(packageName, 0 /* flags */);
if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
return true;
}
@@ -577,11 +581,13 @@ public class BatteryUtils {
// components
// with ComponentInfo#directBootAware == false will be filtered. We should
// explicitly include both direct boot aware and unaware components here.
final List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(launchIntent,
PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_SYSTEM_ONLY);
final List<ResolveInfo> resolveInfos =
mPackageManager.queryIntentActivities(
launchIntent,
PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_DIRECT_BOOT_AWARE
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE
| PackageManager.MATCH_SYSTEM_ONLY);
for (int i = 0, size = resolveInfos.size(); i < size; i++) {
final ResolveInfo resolveInfo = resolveInfos.get(i);
if (ArrayUtils.contains(packageNames, resolveInfo.activityInfo.packageName)) {
@@ -598,8 +604,8 @@ public class BatteryUtils {
*/
public long getAppLongVersionCode(String packageName) {
try {
final PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
0 /* flags */);
final PackageInfo packageInfo =
mPackageManager.getPackageInfo(packageName, 0 /* flags */);
return packageInfo.getLongVersionCode();
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Cannot find package: " + packageName, e);
@@ -626,7 +632,8 @@ public class BatteryUtils {
/** Gets the logging package name. */
public static String getLoggingPackageName(Context context, String originalPackingName) {
return BatteryUtils.isAppInstalledFromGooglePlayStore(context, originalPackingName)
? originalPackingName : PACKAGE_NAME_NONE;
? originalPackingName
: PACKAGE_NAME_NONE;
}
/** Gets the latest sticky battery intent from the Android system. */
@@ -637,12 +644,14 @@ public class BatteryUtils {
/** Gets the current dock defender mode */
public static int getCurrentDockDefenderMode(Context context, BatteryInfo batteryInfo) {
if (batteryInfo.pluggedStatus == BatteryManager.BATTERY_PLUGGED_DOCK) {
if (Settings.Global.getInt(context.getContentResolver(),
SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0) == 1) {
if (Settings.Global.getInt(
context.getContentResolver(), SETTINGS_GLOBAL_DOCK_DEFENDER_BYPASS, 0)
== 1) {
return DockDefenderMode.TEMPORARILY_BYPASSED;
} else if (batteryInfo.isBatteryDefender && FeatureFactory.getFeatureFactory()
.getPowerUsageFeatureProvider()
.isExtraDefend()) {
} else if (batteryInfo.isBatteryDefender
&& FeatureFactory.getFeatureFactory()
.getPowerUsageFeatureProvider()
.isExtraDefend()) {
return DockDefenderMode.ACTIVE;
} else if (!batteryInfo.isBatteryDefender) {
return DockDefenderMode.FUTURE_BYPASS;
@@ -651,59 +660,82 @@ public class BatteryUtils {
return DockDefenderMode.DISABLED;
}
/** Formats elapsed time without commas in between. */
/** Formats elapsed time without commas in between. */
public static CharSequence formatElapsedTimeWithoutComma(
Context context, double millis, boolean withSeconds, boolean collapseTimeUnit) {
return StringUtil.formatElapsedTime(context, millis, withSeconds, collapseTimeUnit)
.toString().replaceAll(",", "");
.toString()
.replaceAll(",", "");
}
/** Builds the battery usage time summary. */
public static String buildBatteryUsageTimeSummary(final Context context, final boolean isSystem,
final long foregroundUsageTimeInMs, final long backgroundUsageTimeInMs,
public static String buildBatteryUsageTimeSummary(
final Context context,
final boolean isSystem,
final long foregroundUsageTimeInMs,
final long backgroundUsageTimeInMs,
final long screenOnTimeInMs) {
StringBuilder summary = new StringBuilder();
if (isSystem) {
final long totalUsageTimeInMs = foregroundUsageTimeInMs + backgroundUsageTimeInMs;
if (totalUsageTimeInMs != 0) {
summary.append(buildBatteryUsageTimeInfo(context, totalUsageTimeInMs,
R.string.battery_usage_total_less_than_one_minute,
R.string.battery_usage_for_total_time));
summary.append(
buildBatteryUsageTimeInfo(
context,
totalUsageTimeInMs,
R.string.battery_usage_total_less_than_one_minute,
R.string.battery_usage_for_total_time));
}
} else {
if (screenOnTimeInMs != 0) {
summary.append(buildBatteryUsageTimeInfo(context, screenOnTimeInMs,
R.string.battery_usage_screen_time_less_than_one_minute,
R.string.battery_usage_screen_time));
summary.append(
buildBatteryUsageTimeInfo(
context,
screenOnTimeInMs,
R.string.battery_usage_screen_time_less_than_one_minute,
R.string.battery_usage_screen_time));
}
if (screenOnTimeInMs != 0 && backgroundUsageTimeInMs != 0) {
summary.append('\n');
}
if (backgroundUsageTimeInMs != 0) {
summary.append(buildBatteryUsageTimeInfo(context, backgroundUsageTimeInMs,
R.string.battery_usage_background_less_than_one_minute,
R.string.battery_usage_for_background_time));
summary.append(
buildBatteryUsageTimeInfo(
context,
backgroundUsageTimeInMs,
R.string.battery_usage_background_less_than_one_minute,
R.string.battery_usage_for_background_time));
}
}
return summary.toString();
}
/** Format the date of battery related info */
public static CharSequence getBatteryInfoFormattedDate(long dateInMs) {
final Instant instant = Instant.ofEpochMilli(dateInMs);
final String localDate = instant.atZone(ZoneId.systemDefault()).toLocalDate().format(
DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG));
final String localDate =
instant.atZone(ZoneId.systemDefault())
.toLocalDate()
.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG));
return localDate;
}
/** Builds the battery usage time information for one timestamp. */
private static String buildBatteryUsageTimeInfo(final Context context, long timeInMs,
final int lessThanOneMinuteResId, final int normalResId) {
private static String buildBatteryUsageTimeInfo(
final Context context,
long timeInMs,
final int lessThanOneMinuteResId,
final int normalResId) {
if (timeInMs < DateUtils.MINUTE_IN_MILLIS) {
return context.getString(lessThanOneMinuteResId);
}
final CharSequence timeSequence = formatElapsedTimeWithoutComma(
context, (double) timeInMs, /*withSeconds=*/ false, /*collapseTimeUnit=*/ false);
final CharSequence timeSequence =
formatElapsedTimeWithoutComma(
context,
(double) timeInMs,
/* withSeconds= */ false,
/* collapseTimeUnit= */ false);
return context.getString(normalResId, timeSequence);
}
}

View File

@@ -40,9 +40,7 @@ public class DebugEstimatesLoader extends AsyncLoaderCompat<List<BatteryInfo>> {
}
@Override
protected void onDiscardResult(List<BatteryInfo> result) {
}
protected void onDiscardResult(List<BatteryInfo> result) {}
@Override
public List<BatteryInfo> loadInBackground() {
@@ -51,29 +49,39 @@ public class DebugEstimatesLoader extends AsyncLoaderCompat<List<BatteryInfo>> {
FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider();
// get stuff we'll need for both BatteryInfo
final long elapsedRealtimeUs = PowerUtil.convertMsToUs(
SystemClock.elapsedRealtime());
Intent batteryBroadcast = getContext().registerReceiver(null,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
final long elapsedRealtimeUs = PowerUtil.convertMsToUs(SystemClock.elapsedRealtime());
Intent batteryBroadcast =
getContext()
.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
BatteryUsageStats batteryUsageStats;
try {
batteryUsageStats = context.getSystemService(BatteryStatsManager.class)
.getBatteryUsageStats();
batteryUsageStats =
context.getSystemService(BatteryStatsManager.class).getBatteryUsageStats();
} catch (RuntimeException e) {
Log.e(TAG, "getBatteryInfo() from getBatteryUsageStats()", e);
// Use default BatteryUsageStats.
batteryUsageStats = new BatteryUsageStats.Builder(new String[0]).build();
}
BatteryInfo oldinfo = BatteryInfo.getBatteryInfoOld(getContext(), batteryBroadcast,
batteryUsageStats, elapsedRealtimeUs, false);
BatteryInfo oldinfo =
BatteryInfo.getBatteryInfoOld(
getContext(),
batteryBroadcast,
batteryUsageStats,
elapsedRealtimeUs,
false);
Estimate estimate = powerUsageFeatureProvider.getEnhancedBatteryPrediction(context);
if (estimate == null) {
estimate = new Estimate(0, false, EstimateKt.AVERAGE_TIME_TO_DISCHARGE_UNKNOWN);
}
BatteryInfo newInfo = BatteryInfo.getBatteryInfo(getContext(), batteryBroadcast,
batteryUsageStats,
estimate, elapsedRealtimeUs, false);
BatteryInfo newInfo =
BatteryInfo.getBatteryInfo(
getContext(),
batteryBroadcast,
batteryUsageStats,
estimate,
elapsedRealtimeUs,
false);
List<BatteryInfo> infos = new ArrayList<>();
infos.add(oldinfo);

View File

@@ -40,23 +40,18 @@ import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
public class HighPowerDetail extends InstrumentedDialogFragment implements OnClickListener,
View.OnClickListener {
public class HighPowerDetail extends InstrumentedDialogFragment
implements OnClickListener, View.OnClickListener {
private static final String ARG_DEFAULT_ON = "default_on";
@VisibleForTesting
PowerAllowlistBackend mBackend;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@VisibleForTesting
String mPackageName;
@VisibleForTesting
int mPackageUid;
@VisibleForTesting PowerAllowlistBackend mBackend;
@VisibleForTesting BatteryUtils mBatteryUtils;
@VisibleForTesting String mPackageName;
@VisibleForTesting int mPackageUid;
private CharSequence mLabel;
private boolean mDefaultOn;
@VisibleForTesting
boolean mIsEnabled;
@VisibleForTesting boolean mIsEnabled;
private Checkable mOptionOn;
private Checkable mOptionOff;
@@ -85,10 +80,13 @@ public class HighPowerDetail extends InstrumentedDialogFragment implements OnCli
}
public Checkable setup(View view, boolean on) {
((TextView) view.findViewById(android.R.id.title)).setText(on
? R.string.ignore_optimizations_on : R.string.ignore_optimizations_off);
((TextView) view.findViewById(android.R.id.summary)).setText(on
? R.string.ignore_optimizations_on_desc : R.string.ignore_optimizations_off_desc);
((TextView) view.findViewById(android.R.id.title))
.setText(on ? R.string.ignore_optimizations_on : R.string.ignore_optimizations_off);
((TextView) view.findViewById(android.R.id.summary))
.setText(
on
? R.string.ignore_optimizations_on_desc
: R.string.ignore_optimizations_off_desc);
view.setClickable(true);
view.setOnClickListener(this);
if (!on && mBackend.isSysAllowlisted(mPackageName)) {
@@ -99,10 +97,11 @@ public class HighPowerDetail extends InstrumentedDialogFragment implements OnCli
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder b = new AlertDialog.Builder(getContext())
.setTitle(mLabel)
.setNegativeButton(R.string.cancel, null)
.setView(R.layout.ignore_optimizations_content);
AlertDialog.Builder b =
new AlertDialog.Builder(getContext())
.setTitle(mLabel)
.setNegativeButton(R.string.cancel, null)
.setView(R.layout.ignore_optimizations_content);
if (!mBackend.isSysAllowlisted(mPackageName)) {
b.setPositiveButton(R.string.done, this);
}
@@ -141,8 +140,8 @@ public class HighPowerDetail extends InstrumentedDialogFragment implements OnCli
if (newValue != oldValue) {
logSpecialPermissionChange(newValue, mPackageName, getContext());
if (newValue) {
mBatteryUtils.setForceAppStandby(mPackageUid, mPackageName,
AppOpsManager.MODE_ALLOWED);
mBatteryUtils.setForceAppStandby(
mPackageUid, mPackageName, AppOpsManager.MODE_ALLOWED);
mBackend.addApp(mPackageName);
} else {
mBackend.removeApp(mPackageName);
@@ -153,10 +152,13 @@ public class HighPowerDetail extends InstrumentedDialogFragment implements OnCli
@VisibleForTesting
static void logSpecialPermissionChange(boolean allowlist, String packageName, Context context) {
int logCategory = allowlist ? SettingsEnums.APP_SPECIAL_PERMISSION_BATTERY_DENY
: SettingsEnums.APP_SPECIAL_PERMISSION_BATTERY_ALLOW;
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider().action(context, logCategory,
packageName);
int logCategory =
allowlist
? SettingsEnums.APP_SPECIAL_PERMISSION_BATTERY_DENY
: SettingsEnums.APP_SPECIAL_PERMISSION_BATTERY_ALLOW;
FeatureFactory.getFeatureFactory()
.getMetricsFeatureProvider()
.action(context, logCategory, packageName);
}
@Override
@@ -177,8 +179,8 @@ public class HighPowerDetail extends InstrumentedDialogFragment implements OnCli
}
@VisibleForTesting
static CharSequence getSummary(Context context, PowerAllowlistBackend powerAllowlist,
String pkg, int uid) {
static CharSequence getSummary(
Context context, PowerAllowlistBackend powerAllowlist, String pkg, int uid) {
return context.getString(
powerAllowlist.isSysAllowlisted(pkg) || powerAllowlist.isDefaultActiveApp(pkg, uid)
? R.string.high_power_system

View File

@@ -47,15 +47,16 @@ import java.util.List;
public class InactiveApps extends SettingsPreferenceFragment
implements Preference.OnPreferenceChangeListener {
private static final CharSequence[] FULL_SETTABLE_BUCKETS_NAMES =
{"ACTIVE", "WORKING_SET", "FREQUENT", "RARE", "RESTRICTED"};
private static final CharSequence[] FULL_SETTABLE_BUCKETS_NAMES = {
"ACTIVE", "WORKING_SET", "FREQUENT", "RARE", "RESTRICTED"
};
private static final CharSequence[] FULL_SETTABLE_BUCKETS_VALUES = {
Integer.toString(STANDBY_BUCKET_ACTIVE),
Integer.toString(STANDBY_BUCKET_WORKING_SET),
Integer.toString(STANDBY_BUCKET_FREQUENT),
Integer.toString(STANDBY_BUCKET_RARE),
Integer.toString(STANDBY_BUCKET_RESTRICTED)
Integer.toString(STANDBY_BUCKET_ACTIVE),
Integer.toString(STANDBY_BUCKET_WORKING_SET),
Integer.toString(STANDBY_BUCKET_FREQUENT),
Integer.toString(STANDBY_BUCKET_RARE),
Integer.toString(STANDBY_BUCKET_RESTRICTED)
};
private UsageStatsManager mUsageStats;
@@ -118,7 +119,7 @@ public class InactiveApps extends SettingsPreferenceFragment
return possibleBuckets;
}
if (minBucket < STANDBY_BUCKET_ACTIVE) {
return new CharSequence[]{};
return new CharSequence[] {};
}
// Use FULL_SETTABLE_BUCKETS_VALUES since we're searching using the int value. The index
// should apply no matter which array we're going to copy from.
@@ -133,13 +134,20 @@ public class InactiveApps extends SettingsPreferenceFragment
static String bucketToName(int bucket) {
switch (bucket) {
case STANDBY_BUCKET_EXEMPTED: return "EXEMPTED";
case STANDBY_BUCKET_ACTIVE: return "ACTIVE";
case STANDBY_BUCKET_WORKING_SET: return "WORKING_SET";
case STANDBY_BUCKET_FREQUENT: return "FREQUENT";
case STANDBY_BUCKET_RARE: return "RARE";
case STANDBY_BUCKET_RESTRICTED: return "RESTRICTED";
case STANDBY_BUCKET_NEVER: return "NEVER";
case STANDBY_BUCKET_EXEMPTED:
return "EXEMPTED";
case STANDBY_BUCKET_ACTIVE:
return "ACTIVE";
case STANDBY_BUCKET_WORKING_SET:
return "WORKING_SET";
case STANDBY_BUCKET_FREQUENT:
return "FREQUENT";
case STANDBY_BUCKET_RARE:
return "RARE";
case STANDBY_BUCKET_RESTRICTED:
return "RESTRICTED";
case STANDBY_BUCKET_NEVER:
return "NEVER";
}
return "";
}
@@ -148,13 +156,13 @@ public class InactiveApps extends SettingsPreferenceFragment
final Resources res = getActivity().getResources();
final int appBucket = mUsageStats.getAppStandbyBucket(p.getKey());
final String bucketName = bucketToName(appBucket);
p.setSummary(res.getString(
com.android.settingslib.R.string.standby_bucket_summary, bucketName));
p.setSummary(
res.getString(com.android.settingslib.R.string.standby_bucket_summary, bucketName));
// Buckets outside of the range of the dynamic ones are only used for special
// purposes and can either not be changed out of, or might have undesirable
// side-effects in combination with other assumptions.
final boolean changeable = appBucket >= STANDBY_BUCKET_ACTIVE
&& appBucket <= STANDBY_BUCKET_RESTRICTED;
final boolean changeable =
appBucket >= STANDBY_BUCKET_ACTIVE && appBucket <= STANDBY_BUCKET_RESTRICTED;
if (changeable) {
p.setValue(Integer.toString(appBucket));
}

View File

@@ -30,10 +30,8 @@ public class OptimizedPreferenceController extends AbstractPreferenceController
private static final String TAG = "OPTIMIZED_PREF";
@VisibleForTesting
static final String KEY_OPTIMIZED_PREF = "optimized_preference";
@VisibleForTesting
BatteryOptimizeUtils mBatteryOptimizeUtils;
@VisibleForTesting static final String KEY_OPTIMIZED_PREF = "optimized_preference";
@VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
public OptimizedPreferenceController(Context context, int uid, String packageName) {
super(context);
@@ -49,9 +47,10 @@ public class OptimizedPreferenceController extends AbstractPreferenceController
public void updateState(Preference preference) {
preference.setEnabled(mBatteryOptimizeUtils.isSelectorPreferenceEnabled());
final boolean isOptimized = mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()
|| mBatteryOptimizeUtils.getAppOptimizationMode()
== BatteryOptimizeUtils.MODE_OPTIMIZED;
final boolean isOptimized =
mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()
|| mBatteryOptimizeUtils.getAppOptimizationMode()
== BatteryOptimizeUtils.MODE_OPTIMIZED;
((SelectorWithWidgetPreference) preference).setChecked(isOptimized);
}

View File

@@ -16,7 +16,6 @@
package com.android.settings.fuelgauge;
import static com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import android.app.Activity;
@@ -53,12 +52,9 @@ import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Allow background usage fragment for each app
*/
public class PowerBackgroundUsageDetail extends DashboardFragment implements
SelectorWithWidgetPreference.OnClickListener,
OnMainSwitchChangeListener {
/** Allow background usage fragment for each app */
public class PowerBackgroundUsageDetail extends DashboardFragment
implements SelectorWithWidgetPreference.OnClickListener, OnMainSwitchChangeListener {
private static final String TAG = "PowerBackgroundUsageDetail";
public static final String EXTRA_UID = "extra_uid";
@@ -74,28 +70,18 @@ public class PowerBackgroundUsageDetail extends DashboardFragment implements
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
@VisibleForTesting
LayoutPreference mHeaderPreference;
@VisibleForTesting
ApplicationsState mState;
@VisibleForTesting
ApplicationsState.AppEntry mAppEntry;
@VisibleForTesting
BatteryOptimizeUtils mBatteryOptimizeUtils;
@VisibleForTesting
SelectorWithWidgetPreference mOptimizePreference;
@VisibleForTesting
SelectorWithWidgetPreference mUnrestrictedPreference;
@VisibleForTesting
MainSwitchPreference mMainSwitchPreference;
@VisibleForTesting
FooterPreference mFooterPreference;
@VisibleForTesting
BackupManager mBackupManager;
@VisibleForTesting
StringBuilder mLogStringBuilder;
@VisibleForTesting
@BatteryOptimizeUtils.OptimizationMode
@VisibleForTesting LayoutPreference mHeaderPreference;
@VisibleForTesting ApplicationsState mState;
@VisibleForTesting ApplicationsState.AppEntry mAppEntry;
@VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
@VisibleForTesting SelectorWithWidgetPreference mOptimizePreference;
@VisibleForTesting SelectorWithWidgetPreference mUnrestrictedPreference;
@VisibleForTesting MainSwitchPreference mMainSwitchPreference;
@VisibleForTesting FooterPreference mFooterPreference;
@VisibleForTesting BackupManager mBackupManager;
@VisibleForTesting StringBuilder mLogStringBuilder;
@VisibleForTesting @BatteryOptimizeUtils.OptimizationMode
int mOptimizationMode = BatteryOptimizeUtils.MODE_UNKNOWN;
@Override
@@ -124,15 +110,18 @@ public class PowerBackgroundUsageDetail extends DashboardFragment implements
initHeader();
mOptimizationMode = mBatteryOptimizeUtils.getAppOptimizationMode();
initFooter();
mExecutor.execute(() -> {
String packageName = BatteryUtils
.getLoggingPackageName(getContext(), mBatteryOptimizeUtils.getPackageName());
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
.action(
getContext(),
SettingsEnums.OPEN_APP_BATTERY_USAGE,
packageName);
});
mExecutor.execute(
() -> {
String packageName =
BatteryUtils.getLoggingPackageName(
getContext(), mBatteryOptimizeUtils.getPackageName());
FeatureFactory.getFeatureFactory()
.getMetricsFeatureProvider()
.action(
getContext(),
SettingsEnums.OPEN_APP_BATTERY_USAGE,
packageName);
});
mLogStringBuilder = new StringBuilder("onResume mode = ").append(mOptimizationMode);
}
@@ -145,14 +134,15 @@ public class PowerBackgroundUsageDetail extends DashboardFragment implements
mLogStringBuilder.append(", onPause mode = ").append(currentOptimizeMode);
logMetricCategory(currentOptimizeMode);
mExecutor.execute(() -> {
BatteryOptimizeLogUtils.writeLog(
getContext().getApplicationContext(),
Action.LEAVE,
BatteryOptimizeLogUtils.getPackageNameWithUserId(
mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()),
mLogStringBuilder.toString());
});
mExecutor.execute(
() -> {
BatteryOptimizeLogUtils.writeLog(
getContext().getApplicationContext(),
Action.LEAVE,
BatteryOptimizeLogUtils.getPackageNameWithUserId(
mBatteryOptimizeUtils.getPackageName(), UserHandle.myUserId()),
mLogStringBuilder.toString());
});
Log.d(TAG, "Leave with mode: " + currentOptimizeMode);
}
@@ -209,8 +199,8 @@ public class PowerBackgroundUsageDetail extends DashboardFragment implements
@VisibleForTesting
void notifyBackupManager() {
if (mOptimizationMode != mBatteryOptimizeUtils.getAppOptimizationMode()) {
final BackupManager backupManager = mBackupManager != null
? mBackupManager : new BackupManager(getContext());
final BackupManager backupManager =
mBackupManager != null ? mBackupManager : new BackupManager(getContext());
backupManager.dataChanged();
}
}
@@ -228,8 +218,7 @@ public class PowerBackgroundUsageDetail extends DashboardFragment implements
}
}
static void startPowerBackgroundUsageDetailPage(
Context context, Bundle args) {
static void startPowerBackgroundUsageDetailPage(Context context, Bundle args) {
new SubSettingLauncher(context)
.setDestination(PowerBackgroundUsageDetail.class.getName())
.setArguments(args)
@@ -242,10 +231,11 @@ public class PowerBackgroundUsageDetail extends DashboardFragment implements
final View appSnippet = mHeaderPreference.findViewById(R.id.entity_header);
final Activity context = getActivity();
final Bundle bundle = getArguments();
EntityHeaderController controller = EntityHeaderController
.newInstance(context, this, appSnippet)
.setButtonActions(EntityHeaderController.ActionType.ACTION_NONE,
EntityHeaderController.ActionType.ACTION_NONE);
EntityHeaderController controller =
EntityHeaderController.newInstance(context, this, appSnippet)
.setButtonActions(
EntityHeaderController.ActionType.ACTION_NONE,
EntityHeaderController.ActionType.ACTION_NONE);
if (mAppEntry == null) {
controller.setLabel(bundle.getString(EXTRA_LABEL));
@@ -275,23 +265,26 @@ public class PowerBackgroundUsageDetail extends DashboardFragment implements
if (mBatteryOptimizeUtils.isDisabledForOptimizeModeOnly()) {
// Present optimized only string when the package name is invalid.
stateString = context.getString(R.string.manager_battery_usage_optimized_only);
footerString = context.getString(
R.string.manager_battery_usage_footer_limited, stateString);
footerString =
context.getString(R.string.manager_battery_usage_footer_limited, stateString);
} else if (mBatteryOptimizeUtils.isSystemOrDefaultApp()) {
// Present unrestricted only string when the package is system or default active app.
stateString = context.getString(R.string.manager_battery_usage_unrestricted_only);
footerString = context.getString(
R.string.manager_battery_usage_footer_limited, stateString);
footerString =
context.getString(R.string.manager_battery_usage_footer_limited, stateString);
} else {
// Present default string to normal app.
footerString = context.getString(R.string.manager_battery_usage_footer);
}
mFooterPreference.setTitle(footerString);
final Intent helpIntent = HelpUtils.getHelpIntent(context, context.getString(
R.string.help_url_app_usage_settings), /*backupContext=*/ "");
final Intent helpIntent =
HelpUtils.getHelpIntent(
context,
context.getString(R.string.help_url_app_usage_settings),
/* backupContext= */ "");
if (helpIntent != null) {
mFooterPreference.setLearnMoreAction(v ->
startActivityForResult(helpIntent, /*requestCode=*/ 0));
mFooterPreference.setLearnMoreAction(
v -> startActivityForResult(helpIntent, /* requestCode= */ 0));
mFooterPreference.setLearnMoreText(
context.getString(R.string.manager_battery_usage_link_a11y));
}
@@ -307,12 +300,13 @@ public class PowerBackgroundUsageDetail extends DashboardFragment implements
mUnrestrictedPreference.setOnClickListener(this);
mMainSwitchPreference.addOnSwitchChangeListener(this);
mBatteryOptimizeUtils = new BatteryOptimizeUtils(
getContext(), getArguments().getInt(EXTRA_UID), packageName);
mBatteryOptimizeUtils =
new BatteryOptimizeUtils(
getContext(), getArguments().getInt(EXTRA_UID), packageName);
}
private void updateSelectorPreferenceState(SelectorWithWidgetPreference preference,
String selectedKey) {
private void updateSelectorPreferenceState(
SelectorWithWidgetPreference preference, String selectedKey) {
preference.setChecked(TextUtils.equals(selectedKey, preference.getKey()));
}
@@ -336,16 +330,19 @@ public class PowerBackgroundUsageDetail extends DashboardFragment implements
return;
}
int finalMetricCategory = metricCategory;
mExecutor.execute(() -> {
String packageName = BatteryUtils
.getLoggingPackageName(getContext(), mBatteryOptimizeUtils.getPackageName());
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
.action(
/* attribution */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
/* action */ finalMetricCategory,
/* pageId */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
packageName,
getArguments().getInt(EXTRA_POWER_USAGE_AMOUNT));
});
mExecutor.execute(
() -> {
String packageName =
BatteryUtils.getLoggingPackageName(
getContext(), mBatteryOptimizeUtils.getPackageName());
FeatureFactory.getFeatureFactory()
.getMetricsFeatureProvider()
.action(
/* attribution */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
/* action */ finalMetricCategory,
/* pageId */ SettingsEnums.OPEN_APP_BATTERY_USAGE,
packageName,
getArguments().getInt(EXTRA_POWER_USAGE_AMOUNT));
});
}
}

View File

@@ -28,19 +28,13 @@ import com.android.settingslib.fuelgauge.Estimate;
import java.util.List;
import java.util.Set;
/**
* Feature Provider used in power usage
*/
/** Feature Provider used in power usage */
public interface PowerUsageFeatureProvider {
/**
* Check whether the battery usage button is enabled in the battery page
*/
/** Check whether the battery usage button is enabled in the battery page */
boolean isBatteryUsageEnabled();
/**
* Check whether the battery tips card is enabled in the battery usage page
*/
/** Check whether the battery tips card is enabled in the battery usage page */
boolean isBatteryTipsEnabled();
/**
@@ -48,39 +42,25 @@ public interface PowerUsageFeatureProvider {
*/
double getBatteryUsageListScreenOnTimeThresholdInMs();
/**
* Returns a threshold (mA) for the minimal comsume power in battery usage list
*/
/** Returns a threshold (mA) for the minimal comsume power in battery usage list */
double getBatteryUsageListConsumePowerThreshold();
/**
* Returns an allowlist of app names combined into the system-apps item
*/
/** Returns an allowlist of app names combined into the system-apps item */
List<String> getSystemAppsAllowlist();
/**
* Check whether location setting is enabled
*/
/** Check whether location setting is enabled */
boolean isLocationSettingEnabled(String[] packages);
/**
* Gets an {@link Intent} to show additional battery info
*/
/** Gets an {@link Intent} to show additional battery info */
Intent getAdditionalBatteryInfoIntent();
/**
* Check whether it is type service
*/
/** Check whether it is type service */
boolean isTypeService(int uid);
/**
* Check whether it is type system
*/
/** Check whether it is type system */
boolean isTypeSystem(int uid, String[] packages);
/**
* Returns an improved prediction for battery time remaining
*/
/** Returns an improved prediction for battery time remaining */
Estimate getEnhancedBatteryPrediction(Context context);
/**
@@ -90,14 +70,10 @@ public interface PowerUsageFeatureProvider {
*/
SparseIntArray getEnhancedBatteryPredictionCurve(Context context, long zeroTime);
/**
* Checks whether the toggle for enhanced battery predictions is enabled
*/
/** Checks whether the toggle for enhanced battery predictions is enabled */
boolean isEnhancedBatteryPredictionEnabled(Context context);
/**
* Checks whether debugging should be enabled for battery estimates
*/
/** Checks whether debugging should be enabled for battery estimates */
boolean isEstimateDebugEnabled();
/**
@@ -115,88 +91,54 @@ public interface PowerUsageFeatureProvider {
*/
String getOldEstimateDebugString(String timeRemaining);
/**
* Checks whether smart battery feature is supported in this device
*/
/** Checks whether smart battery feature is supported in this device */
boolean isSmartBatterySupported();
/**
* Checks whether we should show usage information by slots or not
*/
/** Checks whether we should show usage information by slots or not */
boolean isChartGraphSlotsEnabled(Context context);
/**
* Returns {@code true} if current defender mode is extra defend
*/
/** Returns {@code true} if current defender mode is extra defend */
boolean isExtraDefend();
/**
* Returns {@code true} if delay the hourly job when device is booting
*/
/** Returns {@code true} if delay the hourly job when device is booting */
boolean delayHourlyJobWhenBooting();
/**
* Insert settings configuration data for anomaly detection
*/
/** Insert settings configuration data for anomaly detection */
void insertSettingsData(Context context, double displayDrain);
/**
* Returns {@link Bundle} for settings anomaly detection result
*/
/** Returns {@link Bundle} for settings anomaly detection result */
PowerAnomalyEventList detectSettingsAnomaly(Context context, double displayDrain);
/**
* Gets an intent for one time bypass charge limited to resume charging.
*/
/** Gets an intent for one time bypass charge limited to resume charging. */
Intent getResumeChargeIntent(boolean isDockDefender);
/**
* Returns the intent action used to mark as the full charge start event.
*/
/** Returns the intent action used to mark as the full charge start event. */
String getFullChargeIntentAction();
/**
* Returns {@link Set} for the system component ids which are combined into others
*/
/** Returns {@link Set} for the system component ids which are combined into others */
Set<Integer> getOthersSystemComponentSet();
/**
* Returns {@link Set} for the custom system component names which are combined into others
*/
/** Returns {@link Set} for the custom system component names which are combined into others */
Set<String> getOthersCustomComponentNameSet();
/**
* Returns {@link Set} for hiding system component ids in the usage screen
*/
/** Returns {@link Set} for hiding system component ids in the usage screen */
Set<Integer> getHideSystemComponentSet();
/**
* Returns {@link Set} for hiding application package names in the usage screen
*/
/** Returns {@link Set} for hiding application package names in the usage screen */
Set<String> getHideApplicationSet();
/**
* Returns {@link Set} for hiding applications background usage time
*/
/** Returns {@link Set} for hiding applications background usage time */
Set<String> getHideBackgroundUsageTimeSet();
/**
* Returns {@link Set} for ignoring task root class names for screen on time
*/
/** Returns {@link Set} for ignoring task root class names for screen on time */
Set<String> getIgnoreScreenOnTimeTaskRootSet();
/**
* Returns the customized device build information for data backup
*/
/** Returns the customized device build information for data backup */
String getBuildMetadata1(Context context);
/**
* Returns the customized device build information for data backup
*/
/** Returns the customized device build information for data backup */
String getBuildMetadata2(Context context);
/**
* Whether the app optimization mode is valid to restore
*/
/** Whether the app optimization mode is valid to restore */
boolean isValidToRestoreOptimizationMode(ArrayMap<String, String> deviceInfoMap);
}

View File

@@ -39,8 +39,9 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
private static final String PACKAGE_CALENDAR_PROVIDER = "com.android.providers.calendar";
private static final String PACKAGE_MEDIA_PROVIDER = "com.android.providers.media";
private static final String[] PACKAGES_SYSTEM = {PACKAGE_MEDIA_PROVIDER,
PACKAGE_CALENDAR_PROVIDER, SYSTEMUI_PACKAGE_NAME};
private static final String[] PACKAGES_SYSTEM = {
PACKAGE_MEDIA_PROVIDER, PACKAGE_CALENDAR_PROVIDER, SYSTEMUI_PACKAGE_NAME
};
protected PackageManager mPackageManager;
protected Context mContext;
@@ -137,8 +138,8 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
@Override
public boolean isSmartBatterySupported() {
return mContext.getResources().getBoolean(
com.android.internal.R.bool.config_smart_battery_available);
return mContext.getResources()
.getBoolean(com.android.internal.R.bool.config_smart_battery_available);
}
@Override

View File

@@ -36,12 +36,9 @@ public class PowerUsageTimeController extends BasePreferenceController {
private static final String KEY_SCREEN_TIME_PREF = "battery_usage_screen_time";
private static final String KEY_BACKGROUND_TIME_PREF = "battery_usage_background_time";
@VisibleForTesting
PreferenceCategory mPowerUsageTimeCategory;
@VisibleForTesting
PowerUsageTimePreference mScreenTimePreference;
@VisibleForTesting
PowerUsageTimePreference mBackgroundTimePreference;
@VisibleForTesting PreferenceCategory mPowerUsageTimeCategory;
@VisibleForTesting PowerUsageTimePreference mScreenTimePreference;
@VisibleForTesting PowerUsageTimePreference mBackgroundTimePreference;
public PowerUsageTimeController(Context context) {
super(context, KEY_POWER_USAGE_TIME);
@@ -61,22 +58,37 @@ public class PowerUsageTimeController extends BasePreferenceController {
mPowerUsageTimeCategory.setVisible(false);
}
void handleScreenTimeUpdated(final String slotTime,
final long screenOnTimeInMs, final long backgroundTimeInMs,
final String anomalyHintPrefKey, final String anomalyHintText) {
final boolean isShowScreenOnTime = showTimePreference(
mScreenTimePreference, R.string.power_usage_detail_screen_time,
screenOnTimeInMs, anomalyHintPrefKey, anomalyHintText);
final boolean isShowBackgroundTime = showTimePreference(
mBackgroundTimePreference, R.string.power_usage_detail_background_time,
backgroundTimeInMs, anomalyHintPrefKey, anomalyHintText);
void handleScreenTimeUpdated(
final String slotTime,
final long screenOnTimeInMs,
final long backgroundTimeInMs,
final String anomalyHintPrefKey,
final String anomalyHintText) {
final boolean isShowScreenOnTime =
showTimePreference(
mScreenTimePreference,
R.string.power_usage_detail_screen_time,
screenOnTimeInMs,
anomalyHintPrefKey,
anomalyHintText);
final boolean isShowBackgroundTime =
showTimePreference(
mBackgroundTimePreference,
R.string.power_usage_detail_background_time,
backgroundTimeInMs,
anomalyHintPrefKey,
anomalyHintText);
if (isShowScreenOnTime || isShowBackgroundTime) {
showCategoryTitle(slotTime);
}
}
boolean showTimePreference(PowerUsageTimePreference preference,
int titleResId, long summaryTimeMs, String anomalyHintKey, String anomalyHintText) {
boolean showTimePreference(
PowerUsageTimePreference preference,
int titleResId,
long summaryTimeMs,
String anomalyHintKey,
String anomalyHintText) {
if (preference == null
|| (summaryTimeMs == 0 && !TextUtils.equals(anomalyHintKey, preference.getKey()))) {
return false;
@@ -94,15 +106,19 @@ public class PowerUsageTimeController extends BasePreferenceController {
if (timeInMs < DateUtils.MINUTE_IN_MILLIS) {
return mContext.getString(R.string.power_usage_time_less_than_one_minute);
}
return formatElapsedTimeWithoutComma(mContext, (double) timeInMs,
/*withSeconds=*/ false, /*collapseTimeUnit=*/ false);
return formatElapsedTimeWithoutComma(
mContext,
(double) timeInMs,
/* withSeconds= */ false,
/* collapseTimeUnit= */ false);
}
@VisibleForTesting
void showCategoryTitle(String slotTimestamp) {
mPowerUsageTimeCategory.setTitle(slotTimestamp == null
? mContext.getString(R.string.battery_app_usage)
: mContext.getString(R.string.battery_app_usage_for, slotTimestamp));
mPowerUsageTimeCategory.setTitle(
slotTimestamp == null
? mContext.getString(R.string.battery_app_usage)
: mContext.getString(R.string.battery_app_usage_for, slotTimestamp));
mPowerUsageTimeCategory.setVisible(true);
}
}

View File

@@ -28,18 +28,13 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
/**
* Custom preference for displaying the app power usage time.
*/
/** Custom preference for displaying the app power usage time. */
public class PowerUsageTimePreference extends Preference {
private static final String TAG = "PowerUsageTimePreference";
@VisibleForTesting
CharSequence mTimeTitle;
@VisibleForTesting
CharSequence mTimeSummary;
@VisibleForTesting
CharSequence mAnomalyHintText;
@VisibleForTesting CharSequence mTimeTitle;
@VisibleForTesting CharSequence mTimeSummary;
@VisibleForTesting CharSequence mAnomalyHintText;
public PowerUsageTimePreference(Context context, AttributeSet attrs) {
super(context, attrs);

View File

@@ -31,8 +31,8 @@ import com.android.internal.app.AlertActivity;
import com.android.internal.app.AlertController;
import com.android.settings.R;
public class RequestIgnoreBatteryOptimizations extends AlertActivity implements
DialogInterface.OnClickListener {
public class RequestIgnoreBatteryOptimizations extends AlertActivity
implements DialogInterface.OnClickListener {
private static final String TAG = "RequestIgnoreBatteryOptimizations";
private static final boolean DEBUG = false;
@@ -42,22 +42,24 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity implements
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addSystemFlags(android.view.WindowManager.LayoutParams
.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
getWindow()
.addSystemFlags(
android.view.WindowManager.LayoutParams
.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
mPowerWhitelistManager = getSystemService(PowerWhitelistManager.class);
Uri data = getIntent().getData();
if (data == null) {
debugLog("No data supplied for IGNORE_BATTERY_OPTIMIZATION_SETTINGS in: "
+ getIntent());
debugLog(
"No data supplied for IGNORE_BATTERY_OPTIMIZATION_SETTINGS in: " + getIntent());
finish();
return;
}
mPackageName = data.getSchemeSpecificPart();
if (mPackageName == null) {
debugLog("No data supplied for IGNORE_BATTERY_OPTIMIZATION_SETTINGS in: "
+ getIntent());
debugLog(
"No data supplied for IGNORE_BATTERY_OPTIMIZATION_SETTINGS in: " + getIntent());
finish();
return;
}
@@ -69,11 +71,16 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity implements
return;
}
if (getPackageManager().checkPermission(
Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, mPackageName)
if (getPackageManager()
.checkPermission(
Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
mPackageName)
!= PackageManager.PERMISSION_GRANTED) {
debugLog("Requested package " + mPackageName + " does not hold permission "
+ Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
debugLog(
"Requested package "
+ mPackageName
+ " does not hold permission "
+ Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
finish();
return;
}
@@ -88,9 +95,12 @@ public class RequestIgnoreBatteryOptimizations extends AlertActivity implements
}
final AlertController.AlertParams p = mAlertParams;
final CharSequence appLabel = ai.loadSafeLabel(getPackageManager(),
PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX, PackageItemInfo.SAFE_LABEL_FLAG_TRIM
| PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE);
final CharSequence appLabel =
ai.loadSafeLabel(
getPackageManager(),
PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
PackageItemInfo.SAFE_LABEL_FLAG_TRIM
| PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE);
p.mTitle = getText(R.string.high_power_prompt_title);
p.mMessage = getString(R.string.high_power_prompt_body, appLabel);
p.mPositiveButtonText = getText(R.string.allow);

View File

@@ -35,15 +35,11 @@ import com.android.settingslib.utils.StringUtil;
import java.util.List;
/**
* Controller to change and update the smart battery toggle
*/
/** Controller to change and update the smart battery toggle */
public class RestrictAppPreferenceController extends BasePreferenceController {
@VisibleForTesting
static final String KEY_RESTRICT_APP = "restricted_app";
@VisibleForTesting static final String KEY_RESTRICT_APP = "restricted_app";
@VisibleForTesting
List<AppInfo> mAppInfos;
@VisibleForTesting List<AppInfo> mAppInfos;
private AppOpsManager mAppOpsManager;
private InstrumentedPreferenceFragment mPreferenceFragment;
private UserManager mUserManager;
@@ -65,7 +61,8 @@ public class RestrictAppPreferenceController extends BasePreferenceController {
@Override
public int getAvailabilityStatus() {
return mAppInfos.size() > 0 && !mEnableAppBatteryUsagePage ? AVAILABLE
return mAppInfos.size() > 0 && !mEnableAppBatteryUsagePage
? AVAILABLE
: CONDITIONALLY_UNAVAILABLE;
}
@@ -76,17 +73,17 @@ public class RestrictAppPreferenceController extends BasePreferenceController {
final int num = mAppInfos.size();
// Fragment change RestrictedAppsList after onPause(), UI needs to be updated in onResume()
preference.setVisible(num > 0);
preference.setSummary(StringUtil.getIcuPluralsString(mContext, num,
R.string.restricted_app_summary));
preference.setSummary(
StringUtil.getIcuPluralsString(mContext, num, R.string.restricted_app_summary));
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (getPreferenceKey().equals(preference.getKey())) {
// start fragment
RestrictedAppDetails.startRestrictedAppDetails(mPreferenceFragment,
mAppInfos);
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
RestrictedAppDetails.startRestrictedAppDetails(mPreferenceFragment, mAppInfos);
FeatureFactory.getFeatureFactory()
.getMetricsFeatureProvider()
.action(mContext, SettingsEnums.OPEN_APP_RESTRICTED_LIST);
return true;
}

View File

@@ -52,36 +52,28 @@ import com.android.settingslib.utils.StringUtil;
import java.util.List;
/**
* Fragment to show a list of anomaly apps, where user could handle these anomalies
*/
public class RestrictedAppDetails extends DashboardFragment implements
BatteryTipPreferenceController.BatteryTipListener {
/** Fragment to show a list of anomaly apps, where user could handle these anomalies */
public class RestrictedAppDetails extends DashboardFragment
implements BatteryTipPreferenceController.BatteryTipListener {
public static final String TAG = "RestrictedAppDetails";
@VisibleForTesting
static final String EXTRA_APP_INFO_LIST = "app_info_list";
@VisibleForTesting static final String EXTRA_APP_INFO_LIST = "app_info_list";
private static final String KEY_PREF_RESTRICTED_APP_LIST = "restrict_app_list";
private static final long TIME_NULL = -1;
@VisibleForTesting
List<AppInfo> mAppInfos;
@VisibleForTesting
IconDrawableFactory mIconDrawableFactory;
@VisibleForTesting
PreferenceGroup mRestrictedAppListGroup;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@VisibleForTesting
PackageManager mPackageManager;
@VisibleForTesting
BatteryDatabaseManager mBatteryDatabaseManager;
@VisibleForTesting List<AppInfo> mAppInfos;
@VisibleForTesting IconDrawableFactory mIconDrawableFactory;
@VisibleForTesting PreferenceGroup mRestrictedAppListGroup;
@VisibleForTesting BatteryUtils mBatteryUtils;
@VisibleForTesting PackageManager mPackageManager;
@VisibleForTesting BatteryDatabaseManager mBatteryDatabaseManager;
private MetricsFeatureProvider mMetricsFeatureProvider;
public static void startRestrictedAppDetails(InstrumentedPreferenceFragment fragment,
List<AppInfo> appInfos) {
/** Starts restricted app details page */
public static void startRestrictedAppDetails(
InstrumentedPreferenceFragment fragment, List<AppInfo> appInfos) {
final Bundle args = new Bundle();
args.putParcelableList(EXTRA_APP_INFO_LIST, appInfos);
@@ -104,8 +96,7 @@ public class RestrictedAppDetails extends DashboardFragment implements
mIconDrawableFactory = IconDrawableFactory.newInstance(context);
mBatteryUtils = BatteryUtils.getInstance(context);
mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(context);
mMetricsFeatureProvider =
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
refreshUi();
}
@@ -144,39 +135,50 @@ public class RestrictedAppDetails extends DashboardFragment implements
void refreshUi() {
mRestrictedAppListGroup.removeAll();
final Context context = getPrefContext();
final SparseLongArray timestampArray = mBatteryDatabaseManager
.queryActionTime(AnomalyDatabaseHelper.ActionType.RESTRICTION);
final SparseLongArray timestampArray =
mBatteryDatabaseManager.queryActionTime(
AnomalyDatabaseHelper.ActionType.RESTRICTION);
final long now = System.currentTimeMillis();
for (int i = 0, size = mAppInfos.size(); i < size; i++) {
final CheckBoxPreference checkBoxPreference = new AppCheckBoxPreference(context);
final AppInfo appInfo = mAppInfos.get(i);
try {
final ApplicationInfo applicationInfo = mPackageManager.getApplicationInfoAsUser(
appInfo.packageName, 0 /* flags */, UserHandle.getUserId(appInfo.uid));
final ApplicationInfo applicationInfo =
mPackageManager.getApplicationInfoAsUser(
appInfo.packageName,
0 /* flags */,
UserHandle.getUserId(appInfo.uid));
checkBoxPreference.setChecked(
mBatteryUtils.isForceAppStandbyEnabled(appInfo.uid, appInfo.packageName));
checkBoxPreference.setTitle(mPackageManager.getApplicationLabel(applicationInfo));
checkBoxPreference.setIcon(
Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager,
Utils.getBadgedIcon(
mIconDrawableFactory,
mPackageManager,
appInfo.packageName,
UserHandle.getUserId(appInfo.uid)));
checkBoxPreference.setKey(getKeyFromAppInfo(appInfo));
checkBoxPreference.setOnPreferenceChangeListener((pref, value) -> {
final BatteryTipDialogFragment fragment = createDialogFragment(appInfo,
(Boolean) value);
fragment.setTargetFragment(this, 0 /* requestCode */);
fragment.show(getFragmentManager(), TAG);
mMetricsFeatureProvider.action(getContext(),
SettingsEnums.ACTION_APP_RESTRICTED_LIST_UNCHECKED,
appInfo.packageName);
return false;
});
checkBoxPreference.setOnPreferenceChangeListener(
(pref, value) -> {
final BatteryTipDialogFragment fragment =
createDialogFragment(appInfo, (Boolean) value);
fragment.setTargetFragment(this, 0 /* requestCode */);
fragment.show(getFragmentManager(), TAG);
mMetricsFeatureProvider.action(
getContext(),
SettingsEnums.ACTION_APP_RESTRICTED_LIST_UNCHECKED,
appInfo.packageName);
return false;
});
final long timestamp = timestampArray.get(appInfo.uid, TIME_NULL);
if (timestamp != TIME_NULL) {
checkBoxPreference.setSummary(getString(R.string.restricted_app_time_summary,
StringUtil.formatRelativeTime(context, now - timestamp, false)));
checkBoxPreference.setSummary(
getString(
R.string.restricted_app_time_summary,
StringUtil.formatRelativeTime(
context, now - timestamp, false)));
}
final CharSequence test = checkBoxPreference.getSummaryOn();
mRestrictedAppListGroup.addPreference(checkBoxPreference);
@@ -196,8 +198,9 @@ public class RestrictedAppDetails extends DashboardFragment implements
appInfo = ((UnrestrictAppTip) batteryTip).getUnrestrictAppInfo();
}
CheckBoxPreference preference = (CheckBoxPreference) mRestrictedAppListGroup
.findPreference(getKeyFromAppInfo(appInfo));
CheckBoxPreference preference =
(CheckBoxPreference)
mRestrictedAppListGroup.findPreference(getKeyFromAppInfo(appInfo));
if (preference != null) {
preference.setChecked(isRestricted);
}
@@ -205,12 +208,12 @@ public class RestrictedAppDetails extends DashboardFragment implements
@VisibleForTesting
BatteryTipDialogFragment createDialogFragment(AppInfo appInfo, boolean toRestrict) {
final BatteryTip batteryTip = toRestrict
? new RestrictAppTip(BatteryTip.StateType.NEW, appInfo)
: new UnrestrictAppTip(BatteryTip.StateType.NEW, appInfo);
final BatteryTip batteryTip =
toRestrict
? new RestrictAppTip(BatteryTip.StateType.NEW, appInfo)
: new UnrestrictAppTip(BatteryTip.StateType.NEW, appInfo);
return BatteryTipDialogFragment.newInstance(
batteryTip, getMetricsCategory());
return BatteryTipDialogFragment.newInstance(batteryTip, getMetricsCategory());
}
@VisibleForTesting

View File

@@ -28,11 +28,9 @@ import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory;
/**
* Controller to change and update the smart battery toggle
*/
public class SmartBatteryPreferenceController extends BasePreferenceController implements
Preference.OnPreferenceChangeListener {
/** Controller to change and update the smart battery toggle */
public class SmartBatteryPreferenceController extends BasePreferenceController
implements Preference.OnPreferenceChangeListener {
private static final String KEY_SMART_BATTERY = "smart_battery";
private static final int ON = 1;
@@ -70,16 +68,22 @@ public class SmartBatteryPreferenceController extends BasePreferenceController i
@Override
public void updateState(Preference preference) {
super.updateState(preference);
final boolean smartBatteryOn = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, ON) == ON;
final boolean smartBatteryOn =
Settings.Global.getInt(
mContext.getContentResolver(),
Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED,
ON)
== ON;
((TwoStatePreference) preference).setChecked(smartBatteryOn);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final boolean smartBatteryOn = (Boolean) newValue;
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, smartBatteryOn ? ON : OFF);
Settings.Global.putInt(
mContext.getContentResolver(),
Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED,
smartBatteryOn ? ON : OFF);
return true;
}
}

View File

@@ -32,9 +32,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Fragment to show smart battery and restricted app controls
*/
/** Fragment to show smart battery and restricted app controls */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class SmartBatterySettings extends DashboardFragment {
public static final String TAG = "SmartBatterySettings";
@@ -65,12 +63,12 @@ public class SmartBatterySettings extends DashboardFragment {
}
private static List<AbstractPreferenceController> buildPreferenceControllers(
Context context, SettingsActivity settingsActivity,
Context context,
SettingsActivity settingsActivity,
InstrumentedPreferenceFragment fragment) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
if (settingsActivity != null && fragment != null) {
controllers.add(
new RestrictAppPreferenceController(fragment));
controllers.add(new RestrictAppPreferenceController(fragment));
} else {
controllers.add(new RestrictAppPreferenceController(context));
}

View File

@@ -34,15 +34,13 @@ import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.utils.ThreadUtils;
public class TopLevelBatteryPreferenceController extends BasePreferenceController implements
LifecycleObserver, OnStart, OnStop, BatteryPreferenceController {
public class TopLevelBatteryPreferenceController extends BasePreferenceController
implements LifecycleObserver, OnStart, OnStop, BatteryPreferenceController {
private static final String TAG = "TopLvBatteryPrefControl";
@VisibleForTesting
Preference mPreference;
@VisibleForTesting
protected boolean mIsBatteryPresent = true;
@VisibleForTesting Preference mPreference;
@VisibleForTesting protected boolean mIsBatteryPresent = true;
private final BatteryBroadcastReceiver mBatteryBroadcastReceiver;
@@ -53,28 +51,33 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle
public TopLevelBatteryPreferenceController(Context context, String preferenceKey) {
super(context, preferenceKey);
mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(mContext);
mBatteryBroadcastReceiver.setBatteryChangedListener(type -> {
Log.d(TAG, "onBatteryChanged: type=" + type);
if (type == BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_NOT_PRESENT) {
mIsBatteryPresent = false;
}
BatteryInfo.getBatteryInfo(mContext, info -> {
Log.d(TAG, "getBatteryInfo: " + info);
mBatteryInfo = info;
updateState(mPreference);
// Update the preference summary text to the latest state.
setSummaryAsync(info);
}, true /* shortString */);
});
mBatteryBroadcastReceiver.setBatteryChangedListener(
type -> {
Log.d(TAG, "onBatteryChanged: type=" + type);
if (type == BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_NOT_PRESENT) {
mIsBatteryPresent = false;
}
BatteryInfo.getBatteryInfo(
mContext,
info -> {
Log.d(TAG, "getBatteryInfo: " + info);
mBatteryInfo = info;
updateState(mPreference);
// Update the preference summary text to the latest state.
setSummaryAsync(info);
},
true /* shortString */);
});
mBatteryStatusFeatureProvider = FeatureFactory.getFeatureFactory()
.getBatteryStatusFeatureProvider();
mBatteryStatusFeatureProvider =
FeatureFactory.getFeatureFactory().getBatteryStatusFeatureProvider();
}
@Override
public int getAvailabilityStatus() {
return mContext.getResources().getBoolean(R.bool.config_show_top_level_battery)
? AVAILABLE : UNSUPPORTED_ON_DEVICE;
? AVAILABLE
: UNSUPPORTED_ON_DEVICE;
}
@Override
@@ -106,13 +109,17 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle
return getDashboardLabel(mContext, mBatteryInfo, batteryStatusUpdate);
}
protected CharSequence getDashboardLabel(Context context, BatteryInfo info,
boolean batteryStatusUpdate) {
protected CharSequence getDashboardLabel(
Context context, BatteryInfo info, boolean batteryStatusUpdate) {
if (info == null || context == null) {
return null;
}
Log.d(TAG, "getDashboardLabel: " + mBatteryStatusLabel + " batteryStatusUpdate="
+ batteryStatusUpdate);
Log.d(
TAG,
"getDashboardLabel: "
+ mBatteryStatusLabel
+ " batteryStatusUpdate="
+ batteryStatusUpdate);
if (batteryStatusUpdate) {
setSummaryAsync(info);
@@ -121,19 +128,24 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle
}
private void setSummaryAsync(BatteryInfo info) {
ThreadUtils.postOnBackgroundThread(() -> {
// Return false if built-in status should be used, will use updateBatteryStatus()
// method to inject the customized battery status label.
final boolean triggerBatteryStatusUpdate =
mBatteryStatusFeatureProvider.triggerBatteryStatusUpdate(this, info);
ThreadUtils.postOnMainThread(() -> {
if (!triggerBatteryStatusUpdate) {
mBatteryStatusLabel = null; // will generateLabel()
}
mPreference.setSummary(
mBatteryStatusLabel == null ? generateLabel(info) : mBatteryStatusLabel);
});
});
ThreadUtils.postOnBackgroundThread(
() -> {
// Return false if built-in status should be used, will use
// updateBatteryStatus()
// method to inject the customized battery status label.
final boolean triggerBatteryStatusUpdate =
mBatteryStatusFeatureProvider.triggerBatteryStatusUpdate(this, info);
ThreadUtils.postOnMainThread(
() -> {
if (!triggerBatteryStatusUpdate) {
mBatteryStatusLabel = null; // will generateLabel()
}
mPreference.setSummary(
mBatteryStatusLabel == null
? generateLabel(info)
: mBatteryStatusLabel);
});
});
}
private CharSequence generateLabel(BatteryInfo info) {
@@ -156,9 +168,7 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle
}
}
/**
* Callback which receives text for the label.
*/
/** Callback which receives text for the label. */
@Override
public void updateBatteryStatus(String label, BatteryInfo info) {
mBatteryStatusLabel = label; // Null if adaptive charging is not active

View File

@@ -30,8 +30,7 @@ public class UnrestrictedPreferenceController extends AbstractPreferenceControll
private static final String TAG = "UNRESTRICTED_PREF";
@VisibleForTesting
static final String KEY_UNRESTRICTED_PREF = "unrestricted_preference";
@VisibleForTesting static final String KEY_UNRESTRICTED_PREF = "unrestricted_preference";
@VisibleForTesting BatteryOptimizeUtils mBatteryOptimizeUtils;
@@ -44,8 +43,9 @@ public class UnrestrictedPreferenceController extends AbstractPreferenceControll
public void updateState(Preference preference) {
preference.setEnabled(mBatteryOptimizeUtils.isSelectorPreferenceEnabled());
final boolean isUnrestricted = mBatteryOptimizeUtils.getAppOptimizationMode()
== BatteryOptimizeUtils.MODE_UNRESTRICTED;
final boolean isUnrestricted =
mBatteryOptimizeUtils.getAppOptimizationMode()
== BatteryOptimizeUtils.MODE_UNRESTRICTED;
((SelectorWithWidgetPreference) preference).setChecked(isUnrestricted);
}

View File

@@ -37,12 +37,9 @@ import com.android.settingslib.core.lifecycle.events.OnStop;
import com.android.settingslib.fuelgauge.BatterySaverUtils;
import com.android.settingslib.widget.MainSwitchPreference;
/**
* Controller to update the battery saver button
*/
public class BatterySaverButtonPreferenceController extends
TogglePreferenceController implements LifecycleObserver, OnStart, OnStop,
BatterySaverReceiver.BatterySaverListener {
/** Controller to update the battery saver button */
public class BatterySaverButtonPreferenceController extends TogglePreferenceController
implements LifecycleObserver, OnStart, OnStop, BatterySaverReceiver.BatterySaverListener {
private static final long SWITCH_ANIMATION_DURATION = 350L;
private final BatterySaverReceiver mBatterySaverReceiver;
@@ -104,8 +101,8 @@ public class BatterySaverButtonPreferenceController extends
@Override
public boolean setChecked(boolean stateOn) {
return BatterySaverUtils.setPowerSaveMode(mContext, stateOn,
false /* needFirstTimeWarning */, SAVER_ENABLED_SETTINGS);
return BatterySaverUtils.setPowerSaveMode(
mContext, stateOn, false /* needFirstTimeWarning */, SAVER_ENABLED_SETTINGS);
}
@Override
@@ -115,8 +112,7 @@ public class BatterySaverButtonPreferenceController extends
@Override
public void onPowerSaveModeChanged() {
mHandler.postDelayed(() -> onPowerSaveModeChangedInternal(),
SWITCH_ANIMATION_DURATION);
mHandler.postDelayed(() -> onPowerSaveModeChangedInternal(), SWITCH_ANIMATION_DURATION);
}
private void onPowerSaveModeChangedInternal() {

View File

@@ -32,17 +32,14 @@ import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.fuelgauge.BatterySaverUtils;
/**
* Simple controller to navigate users to the scheduling page from
* "Settings > Battery > Battery Saver". Also updates the summary for preference based on
* the currently selected settings.
* Simple controller to navigate users to the scheduling page from "Settings > Battery > Battery
* Saver". Also updates the summary for preference based on the currently selected settings.
*/
public class BatterySaverSchedulePreferenceController extends BasePreferenceController {
@VisibleForTesting
Preference mBatterySaverSchedulePreference;
@VisibleForTesting Preference mBatterySaverSchedulePreference;
public static final String KEY_BATTERY_SAVER_SCHEDULE = "battery_saver_schedule";
public BatterySaverSchedulePreferenceController(Context context) {
super(context, KEY_BATTERY_SAVER_SCHEDULE);
BatterySaverUtils.revertScheduleToNoneIfNeeded(context);
@@ -66,7 +63,8 @@ public class BatterySaverSchedulePreferenceController extends BasePreferenceCont
if (KEY_PERCENTAGE.equals(mode)) {
final int threshold =
Settings.Global.getInt(resolver, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0);
return mContext.getString(R.string.battery_saver_auto_percentage_summary,
return mContext.getString(
R.string.battery_saver_auto_percentage_summary,
Utils.formatPercentage(threshold));
}
return mContext.getText(R.string.battery_saver_auto_no_schedule);

View File

@@ -31,12 +31,12 @@ import com.android.settingslib.fuelgauge.BatterySaverUtils;
/**
* Responds to user actions in the Settings > Battery > Set a Schedule Screen
*
* Note that this is not a preference controller since that screen does not inherit from
* <p>Note that this is not a preference controller since that screen does not inherit from
* DashboardFragment.
*
* Will call the appropriate power manager APIs and modify the correct settings to enable
* users to control their automatic battery saver toggling preferences.
* See {@link Settings.Global#AUTOMATIC_POWER_SAVE_MODE} for more details.
* <p>Will call the appropriate power manager APIs and modify the correct settings to enable users
* to control their automatic battery saver toggling preferences. See {@link
* Settings.Global#AUTOMATIC_POWER_SAVE_MODE} for more details.
*/
public class BatterySaverScheduleRadioButtonsController {
private static final String TAG = "BatterySaverScheduleRadioButtonsController";
@@ -46,8 +46,8 @@ public class BatterySaverScheduleRadioButtonsController {
private Context mContext;
private BatterySaverScheduleSeekBarController mSeekBarController;
public BatterySaverScheduleRadioButtonsController(Context context,
BatterySaverScheduleSeekBarController seekbar) {
public BatterySaverScheduleRadioButtonsController(
Context context, BatterySaverScheduleSeekBarController seekbar) {
mContext = context;
mSeekBarController = seekbar;
}
@@ -67,10 +67,11 @@ public class BatterySaverScheduleRadioButtonsController {
case KEY_PERCENTAGE:
triggerLevel = TRIGGER_LEVEL_MIN;
confirmationExtras.putBoolean(BatterySaverUtils.EXTRA_CONFIRM_TEXT_ONLY, true);
confirmationExtras.putInt(BatterySaverUtils.EXTRA_POWER_SAVE_MODE_TRIGGER,
confirmationExtras.putInt(
BatterySaverUtils.EXTRA_POWER_SAVE_MODE_TRIGGER,
PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE);
confirmationExtras.putInt(BatterySaverUtils.EXTRA_POWER_SAVE_MODE_TRIGGER_LEVEL,
triggerLevel);
confirmationExtras.putInt(
BatterySaverUtils.EXTRA_POWER_SAVE_MODE_TRIGGER_LEVEL, triggerLevel);
break;
default:
throw new IllegalStateException(
@@ -79,7 +80,7 @@ public class BatterySaverScheduleRadioButtonsController {
if (!TextUtils.equals(key, KEY_NO_SCHEDULE)
&& BatterySaverUtils.maybeShowBatterySaverConfirmation(
mContext, confirmationExtras)) {
mContext, confirmationExtras)) {
// reset this if we need to show the confirmation message
mode = PowerManager.POWER_SAVE_MODE_TRIGGER_PERCENTAGE;
triggerLevel = 0;

View File

@@ -35,30 +35,28 @@ import com.android.settings.widget.SeekBarPreference;
import com.android.settingslib.fuelgauge.BatterySaverUtils;
/**
* Responds to user actions in the Settings > Battery > Set a Schedule Screen for the seekbar.
* Note that this seekbar is only visible when the radio button selected is "Percentage".
* Responds to user actions in the Settings > Battery > Set a Schedule Screen for the seekbar. Note
* that this seekbar is only visible when the radio button selected is "Percentage".
*
* Note that this is not a preference controller since that screen does not inherit from
* <p>Note that this is not a preference controller since that screen does not inherit from
* DashboardFragment.
*
* Will call the appropriate power manager APIs and modify the correct settings to enable
* users to control their automatic battery saver toggling preferences.
* See {@link Settings.Global#AUTOMATIC_POWER_SAVE_MODE} for more details.
* <p>Will call the appropriate power manager APIs and modify the correct settings to enable users
* to control their automatic battery saver toggling preferences. See {@link
* Settings.Global#AUTOMATIC_POWER_SAVE_MODE} for more details.
*/
public class BatterySaverScheduleSeekBarController implements
OnPreferenceChangeListener, OnSeekBarChangeListener {
public class BatterySaverScheduleSeekBarController
implements OnPreferenceChangeListener, OnSeekBarChangeListener {
public static final int MAX_SEEKBAR_VALUE = 15;
public static final int MIN_SEEKBAR_VALUE = 2;
public static final String KEY_BATTERY_SAVER_SEEK_BAR = "battery_saver_seek_bar";
private static final int LEVEL_UNIT_SCALE = 5;
@VisibleForTesting
public SeekBarPreference mSeekBarPreference;
@VisibleForTesting public SeekBarPreference mSeekBarPreference;
private Context mContext;
@VisibleForTesting
int mPercentage;
@VisibleForTesting int mPercentage;
public BatterySaverScheduleSeekBarController(Context context) {
mContext = context;
@@ -93,7 +91,8 @@ public class BatterySaverScheduleSeekBarController implements
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (mPercentage > 0) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.putInt(
mContext.getContentResolver(),
Global.LOW_POWER_MODE_TRIGGER_LEVEL,
mPercentage);
}
@@ -108,8 +107,7 @@ public class BatterySaverScheduleSeekBarController implements
final int currentSeekbarValue = Math.max(threshold / 5, MIN_SEEKBAR_VALUE);
mSeekBarPreference.setVisible(true);
mSeekBarPreference.setProgress(currentSeekbarValue);
final CharSequence stateDescription = formatStateDescription(
currentSeekbarValue * 5);
final CharSequence stateDescription = formatStateDescription(currentSeekbarValue * 5);
mSeekBarPreference.setTitle(stateDescription);
mSeekBarPreference.overrideSeekBarStateDescription(stateDescription);
} else {
@@ -130,7 +128,7 @@ public class BatterySaverScheduleSeekBarController implements
}
private CharSequence formatStateDescription(int percentage) {
return mContext.getString(R.string.battery_saver_seekbar_title,
Utils.formatPercentage(percentage));
return mContext.getString(
R.string.battery_saver_seekbar_title, Utils.formatPercentage(percentage));
}
}

View File

@@ -49,32 +49,32 @@ import com.google.common.collect.Lists;
import java.util.List;
/**
* Fragment that allows users to customize their automatic battery saver mode settings.
*
* Location: Settings > Battery > Battery Saver > Set a Schedule
* Fragment that allows users to customize their automatic battery saver mode settings. <br>
* <br>
* Location: Settings > Battery > Battery Saver > Set a Schedule <br>
* See {@link BatterySaverSchedulePreferenceController} for the controller that manages navigation
* to this screen from "Settings > Battery > Battery Saver" and the summary.
* See {@link BatterySaverScheduleRadioButtonsController} &
* {@link BatterySaverScheduleSeekBarController} for the controller that manages user
* interactions in this screen.
* to this screen from "Settings > Battery > Battery Saver" and the summary. <br>
* See {@link BatterySaverScheduleRadioButtonsController} & {@link
* BatterySaverScheduleSeekBarController} for the controller that manages user interactions in this
* screen.
*/
public class BatterySaverScheduleSettings extends RadioButtonPickerFragment {
public BatterySaverScheduleRadioButtonsController mRadioButtonController;
@VisibleForTesting
Context mContext;
@VisibleForTesting Context mContext;
private int mSaverPercentage;
private String mSaverScheduleKey;
private BatterySaverScheduleSeekBarController mSeekBarController;
@VisibleForTesting
final ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange, Uri uri) {
getPreferenceScreen().removeAll();
updateCandidates();
}
};
final ContentObserver mSettingsObserver =
new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange, Uri uri) {
getPreferenceScreen().removeAll();
updateCandidates();
}
};
@Override
protected int getPreferenceScreenResId() {
@@ -85,18 +85,19 @@ public class BatterySaverScheduleSettings extends RadioButtonPickerFragment {
public void onAttach(Context context) {
super.onAttach(context);
mSeekBarController = new BatterySaverScheduleSeekBarController(context);
mRadioButtonController = new BatterySaverScheduleRadioButtonsController(
context, mSeekBarController);
mRadioButtonController =
new BatterySaverScheduleRadioButtonsController(context, mSeekBarController);
mContext = context;
}
@Override
public void onResume() {
super.onResume();
mContext.getContentResolver().registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED),
false,
mSettingsObserver);
mContext.getContentResolver()
.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED),
false,
mSettingsObserver);
mSaverScheduleKey = BatterySaverUtils.getBatterySaverScheduleKey(mContext);
mSaverPercentage = getSaverPercentage();
}
@@ -124,24 +125,30 @@ public class BatterySaverScheduleSettings extends RadioButtonPickerFragment {
protected List<? extends CandidateInfo> getCandidates() {
Context context = getContext();
List<CandidateInfo> candidates = Lists.newArrayList();
candidates.add(new BatterySaverScheduleCandidateInfo(
context.getText(R.string.battery_saver_auto_no_schedule),
/* summary */ null,
KEY_NO_SCHEDULE,
/* enabled */ true));
candidates.add(
new BatterySaverScheduleCandidateInfo(
context.getText(R.string.battery_saver_auto_no_schedule),
/* summary */ null,
KEY_NO_SCHEDULE,
/* enabled */ true));
BatterySaverUtils.revertScheduleToNoneIfNeeded(context);
candidates.add(new BatterySaverScheduleCandidateInfo(
context.getText(R.string.battery_saver_auto_percentage),
/* summary */ null,
KEY_PERCENTAGE,
/* enabled */ true));
candidates.add(
new BatterySaverScheduleCandidateInfo(
context.getText(R.string.battery_saver_auto_percentage),
/* summary */ null,
KEY_PERCENTAGE,
/* enabled */ true));
return candidates;
}
@Override
public void bindPreferenceExtra(SelectorWithWidgetPreference pref, String key,
CandidateInfo info, String defaultKey, String systemDefaultKey) {
public void bindPreferenceExtra(
SelectorWithWidgetPreference pref,
String key,
CandidateInfo info,
String defaultKey,
String systemDefaultKey) {
final BatterySaverScheduleCandidateInfo candidateInfo =
(BatterySaverScheduleCandidateInfo) info;
final CharSequence summary = candidateInfo.getSummary();
@@ -174,14 +181,16 @@ public class BatterySaverScheduleSettings extends RadioButtonPickerFragment {
private void logPowerSaver() {
final int currentSaverPercentage = getSaverPercentage();
final String currentSaverScheduleKey = BatterySaverUtils.getBatterySaverScheduleKey(
mContext);
final String currentSaverScheduleKey =
BatterySaverUtils.getBatterySaverScheduleKey(mContext);
if (mSaverScheduleKey.equals(currentSaverScheduleKey)
&& mSaverPercentage == currentSaverPercentage) {
return;
}
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
.action(SettingsEnums.FUELGAUGE_BATTERY_SAVER,
FeatureFactory.getFeatureFactory()
.getMetricsFeatureProvider()
.action(
SettingsEnums.FUELGAUGE_BATTERY_SAVER,
SettingsEnums.FIELD_BATTERY_SAVER_SCHEDULE_TYPE,
SettingsEnums.FIELD_BATTERY_SAVER_PERCENTAGE_VALUE,
currentSaverScheduleKey,
@@ -189,8 +198,8 @@ public class BatterySaverScheduleSettings extends RadioButtonPickerFragment {
}
private int getSaverPercentage() {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, -1);
return Settings.Global.getInt(
mContext.getContentResolver(), Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, -1);
}
static class BatterySaverScheduleCandidateInfo extends CandidateInfo {
@@ -199,8 +208,8 @@ public class BatterySaverScheduleSettings extends RadioButtonPickerFragment {
private final CharSequence mSummary;
private final String mKey;
BatterySaverScheduleCandidateInfo(CharSequence label, CharSequence summary, String key,
boolean enabled) {
BatterySaverScheduleCandidateInfo(
CharSequence label, CharSequence summary, String key, boolean enabled) {
super(enabled);
mLabel = label;
mKey = key;

View File

@@ -28,9 +28,7 @@ import com.android.settingslib.HelpUtils;
import com.android.settingslib.search.SearchIndexable;
import com.android.settingslib.widget.FooterPreference;
/**
* Battery saver settings page
*/
/** Battery saver settings page */
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class BatterySaverSettings extends DashboardFragment {
private static final String TAG = "BatterySaverSettings";
@@ -63,9 +61,7 @@ public class BatterySaverSettings extends DashboardFragment {
return R.string.help_url_battery_saver_settings;
}
/**
* For Search.
*/
/** For Search. */
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.battery_saver_settings);
@@ -83,13 +79,17 @@ public class BatterySaverSettings extends DashboardFragment {
void addHelpLink() {
FooterPreference pref = getPreferenceScreen().findPreference(KEY_FOOTER_PREFERENCE);
if (pref != null) {
pref.setLearnMoreAction(v -> {
mMetricsFeatureProvider.action(getContext(),
SettingsEnums.ACTION_APP_BATTERY_LEARN_MORE);
startActivityForResult(HelpUtils.getHelpIntent(getContext(),
getString(R.string.help_url_battery_saver_settings),
/*backupContext=*/ ""), /*requestCode=*/ 0);
});
pref.setLearnMoreAction(
v -> {
mMetricsFeatureProvider.action(
getContext(), SettingsEnums.ACTION_APP_BATTERY_LEARN_MORE);
startActivityForResult(
HelpUtils.getHelpIntent(
getContext(),
getString(R.string.help_url_battery_saver_settings),
/* backupContext= */ ""),
/* requestCode= */ 0);
});
pref.setLearnMoreText(getString(R.string.battery_saver_link_a11y));
}
}

View File

@@ -12,8 +12,8 @@ import com.android.settings.Utils;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.TogglePreferenceController;
public class BatterySaverStickyPreferenceController extends TogglePreferenceController implements
PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
public class BatterySaverStickyPreferenceController extends TogglePreferenceController
implements PreferenceControllerMixin, Preference.OnPreferenceChangeListener {
private static final int DEFAULT_STICKY_SHUTOFF_LEVEL = 90;
private Context mContext;
@@ -25,34 +25,46 @@ public class BatterySaverStickyPreferenceController extends TogglePreferenceCont
@Override
public boolean isChecked() {
return Settings.Global.getInt(mContext.getContentResolver(),
Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1) == 1;
return Settings.Global.getInt(
mContext.getContentResolver(),
Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
1)
== 1;
}
@Override
public boolean setChecked(boolean isChecked) {
Settings.Global.putInt(mContext.getContentResolver(),
Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
isChecked ? 1 : 0);
Settings.Global.putInt(
mContext.getContentResolver(),
Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
isChecked ? 1 : 0);
return true;
}
@Override
protected void refreshSummary(Preference preference) {
super.refreshSummary(preference);
final int stickyShutoffLevel = Settings.Global.getInt(mContext.getContentResolver(),
Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL, DEFAULT_STICKY_SHUTOFF_LEVEL);
final int stickyShutoffLevel =
Settings.Global.getInt(
mContext.getContentResolver(),
Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_LEVEL,
DEFAULT_STICKY_SHUTOFF_LEVEL);
final String formatPercentage = Utils.formatPercentage(stickyShutoffLevel);
preference.setTitle(mContext.getString(R.string.battery_saver_sticky_title_percentage,
formatPercentage));
preference.setSummary(mContext.getString(R.string.battery_saver_sticky_description_new,
formatPercentage));
preference.setTitle(
mContext.getString(
R.string.battery_saver_sticky_title_percentage, formatPercentage));
preference.setSummary(
mContext.getString(
R.string.battery_saver_sticky_description_new, formatPercentage));
}
@Override
public void updateState(Preference preference) {
int setting = Settings.Global.getInt(mContext.getContentResolver(),
Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED, 1);
int setting =
Settings.Global.getInt(
mContext.getContentResolver(),
Global.LOW_POWER_MODE_STICKY_AUTO_DISABLE_ENABLED,
1);
((TwoStatePreference) preference).setChecked(setting == 1);
refreshSummary(preference);

View File

@@ -35,8 +35,7 @@ import java.util.concurrent.TimeUnit;
public class AnomalyCleanupJobService extends JobService {
private static final String TAG = "AnomalyCleanUpJobService";
@VisibleForTesting
static final long CLEAN_UP_FREQUENCY_MS = TimeUnit.DAYS.toMillis(1);
@VisibleForTesting static final long CLEAN_UP_FREQUENCY_MS = TimeUnit.DAYS.toMillis(1);
public static void scheduleCleanUp(Context context) {
final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
@@ -52,23 +51,24 @@ public class AnomalyCleanupJobService extends JobService {
// Don't schedule it if it already exists, to make sure it runs periodically even after
// reboot
if (pending == null && jobScheduler.schedule(jobBuilder.build())
!= JobScheduler.RESULT_SUCCESS) {
if (pending == null
&& jobScheduler.schedule(jobBuilder.build()) != JobScheduler.RESULT_SUCCESS) {
Log.i(TAG, "Anomaly clean up job service schedule failed.");
}
}
@Override
public boolean onStartJob(JobParameters params) {
final BatteryDatabaseManager batteryDatabaseManager = BatteryDatabaseManager
.getInstance(this);
final BatteryDatabaseManager batteryDatabaseManager =
BatteryDatabaseManager.getInstance(this);
final BatteryTipPolicy policy = new BatteryTipPolicy(this);
ThreadUtils.postOnBackgroundThread(() -> {
batteryDatabaseManager.deleteAllAnomaliesBeforeTimeStamp(
System.currentTimeMillis() - TimeUnit.DAYS.toMillis(
policy.dataHistoryRetainDay));
jobFinished(params, false /* wantsReschedule */);
});
ThreadUtils.postOnBackgroundThread(
() -> {
batteryDatabaseManager.deleteAllAnomaliesBeforeTimeStamp(
System.currentTimeMillis()
- TimeUnit.DAYS.toMillis(policy.dataHistoryRetainDay));
jobFinished(params, false /* wantsReschedule */);
});
return true;
}

View File

@@ -44,8 +44,7 @@ public class AnomalyConfigJobService extends JobService {
public static final String KEY_ANOMALY_CONFIG_VERSION = "anomaly_config_version";
private static final int DEFAULT_VERSION = 0;
@VisibleForTesting
static final long CONFIG_UPDATE_FREQUENCY_MS = TimeUnit.DAYS.toMillis(1);
@VisibleForTesting static final long CONFIG_UPDATE_FREQUENCY_MS = TimeUnit.DAYS.toMillis(1);
public static void scheduleConfigUpdate(Context context) {
final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
@@ -61,24 +60,25 @@ public class AnomalyConfigJobService extends JobService {
// Don't schedule it if it already exists, to make sure it runs periodically even after
// reboot
if (pending == null && jobScheduler.schedule(jobBuilder.build())
!= JobScheduler.RESULT_SUCCESS) {
if (pending == null
&& jobScheduler.schedule(jobBuilder.build()) != JobScheduler.RESULT_SUCCESS) {
Log.i(TAG, "Anomaly config update job service schedule failed.");
}
}
@Override
public boolean onStartJob(JobParameters params) {
ThreadUtils.postOnBackgroundThread(() -> {
final StatsManager statsManager = getSystemService(StatsManager.class);
checkAnomalyConfig(statsManager);
try {
BatteryTipUtils.uploadAnomalyPendingIntent(this, statsManager);
} catch (StatsManager.StatsUnavailableException e) {
Log.w(TAG, "Failed to uploadAnomalyPendingIntent.", e);
}
jobFinished(params, false /* wantsReschedule */);
});
ThreadUtils.postOnBackgroundThread(
() -> {
final StatsManager statsManager = getSystemService(StatsManager.class);
checkAnomalyConfig(statsManager);
try {
BatteryTipUtils.uploadAnomalyPendingIntent(this, statsManager);
} catch (StatsManager.StatsUnavailableException e) {
Log.w(TAG, "Failed to uploadAnomalyPendingIntent.", e);
}
jobFinished(params, false /* wantsReschedule */);
});
return true;
}
@@ -90,37 +90,48 @@ public class AnomalyConfigJobService extends JobService {
@VisibleForTesting
synchronized void checkAnomalyConfig(StatsManager statsManager) {
final SharedPreferences sharedPreferences = getSharedPreferences(PREF_DB,
Context.MODE_PRIVATE);
final int currentVersion = sharedPreferences.getInt(KEY_ANOMALY_CONFIG_VERSION,
DEFAULT_VERSION);
final int newVersion = Settings.Global.getInt(getContentResolver(),
Settings.Global.ANOMALY_CONFIG_VERSION, DEFAULT_VERSION);
final String rawConfig = Settings.Global.getString(getContentResolver(),
Settings.Global.ANOMALY_CONFIG);
final SharedPreferences sharedPreferences =
getSharedPreferences(PREF_DB, Context.MODE_PRIVATE);
final int currentVersion =
sharedPreferences.getInt(KEY_ANOMALY_CONFIG_VERSION, DEFAULT_VERSION);
final int newVersion =
Settings.Global.getInt(
getContentResolver(),
Settings.Global.ANOMALY_CONFIG_VERSION,
DEFAULT_VERSION);
final String rawConfig =
Settings.Global.getString(getContentResolver(), Settings.Global.ANOMALY_CONFIG);
Log.i(TAG, "CurrentVersion: " + currentVersion + " new version: " + newVersion);
if (newVersion > currentVersion) {
try {
statsManager.removeConfig(StatsManagerConfig.ANOMALY_CONFIG_KEY);
} catch (StatsManager.StatsUnavailableException e) {
Log.i(TAG, "When updating anomaly config, failed to first remove the old config "
+ StatsManagerConfig.ANOMALY_CONFIG_KEY, e);
Log.i(
TAG,
"When updating anomaly config, failed to first remove the old config "
+ StatsManagerConfig.ANOMALY_CONFIG_KEY,
e);
}
if (!TextUtils.isEmpty(rawConfig)) {
try {
final byte[] config = Base64.decode(rawConfig, Base64.DEFAULT);
statsManager.addConfig(StatsManagerConfig.ANOMALY_CONFIG_KEY, config);
Log.i(TAG, "Upload the anomaly config. configKey: "
+ StatsManagerConfig.ANOMALY_CONFIG_KEY);
Log.i(
TAG,
"Upload the anomaly config. configKey: "
+ StatsManagerConfig.ANOMALY_CONFIG_KEY);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt(KEY_ANOMALY_CONFIG_VERSION, newVersion);
editor.commit();
} catch (IllegalArgumentException e) {
Log.e(TAG, "Anomaly raw config is in wrong format", e);
} catch (StatsManager.StatsUnavailableException e) {
Log.i(TAG, "Upload of anomaly config failed for configKey "
+ StatsManagerConfig.ANOMALY_CONFIG_KEY, e);
Log.i(
TAG,
"Upload of anomaly config failed for configKey "
+ StatsManagerConfig.ANOMALY_CONFIG_KEY,
e);
}
}
}

View File

@@ -23,8 +23,8 @@ import android.content.Intent;
import android.util.Log;
/**
* Receive broadcast when {@link StatsManager} restart, then check the anomaly config and
* prepare info for {@link StatsManager}
* Receive broadcast when {@link StatsManager} restart, then check the anomaly config and prepare
* info for {@link StatsManager}
*/
public class AnomalyConfigReceiver extends BroadcastReceiver {
private static final String TAG = "AnomalyConfigReceiver";

View File

@@ -26,9 +26,7 @@ import androidx.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Database controls the anomaly logging(e.g. packageName, anomalyType and time)
*/
/** Database controls the anomaly logging(e.g. packageName, anomalyType and time) */
public class AnomalyDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "BatteryDatabaseHelper";
@@ -36,9 +34,7 @@ public class AnomalyDatabaseHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 5;
@Retention(RetentionPolicy.SOURCE)
@IntDef({State.NEW,
State.HANDLED,
State.AUTO_HANDLED})
@IntDef({State.NEW, State.HANDLED, State.AUTO_HANDLED})
public @interface State {
int NEW = 0;
int HANDLED = 1;
@@ -57,81 +53,92 @@ public class AnomalyDatabaseHelper extends SQLiteOpenHelper {
}
public interface AnomalyColumns {
/**
* The package name of the anomaly app
*/
/** The package name of the anomaly app */
String PACKAGE_NAME = "package_name";
/**
* The uid of the anomaly app
*/
/** The uid of the anomaly app */
String UID = "uid";
/**
* The type of the anomaly app
*
* @see StatsManagerConfig.AnomalyType
*/
String ANOMALY_TYPE = "anomaly_type";
/**
* The state of the anomaly app
*
* @see State
*/
String ANOMALY_STATE = "anomaly_state";
/**
* The time when anomaly happens
*/
/** The time when anomaly happens */
String TIME_STAMP_MS = "time_stamp_ms";
}
private static final String CREATE_ANOMALY_TABLE =
"CREATE TABLE " + Tables.TABLE_ANOMALY +
"(" +
AnomalyColumns.UID +
" INTEGER NOT NULL, " +
AnomalyColumns.PACKAGE_NAME +
" TEXT, " +
AnomalyColumns.ANOMALY_TYPE +
" INTEGER NOT NULL, " +
AnomalyColumns.ANOMALY_STATE +
" INTEGER NOT NULL, " +
AnomalyColumns.TIME_STAMP_MS +
" INTEGER NOT NULL, " +
" PRIMARY KEY (" + AnomalyColumns.UID + "," + AnomalyColumns.ANOMALY_TYPE + ","
+ AnomalyColumns.ANOMALY_STATE + "," + AnomalyColumns.TIME_STAMP_MS + ")"
"CREATE TABLE "
+ Tables.TABLE_ANOMALY
+ "("
+ AnomalyColumns.UID
+ " INTEGER NOT NULL, "
+ AnomalyColumns.PACKAGE_NAME
+ " TEXT, "
+ AnomalyColumns.ANOMALY_TYPE
+ " INTEGER NOT NULL, "
+ AnomalyColumns.ANOMALY_STATE
+ " INTEGER NOT NULL, "
+ AnomalyColumns.TIME_STAMP_MS
+ " INTEGER NOT NULL, "
+ " PRIMARY KEY ("
+ AnomalyColumns.UID
+ ","
+ AnomalyColumns.ANOMALY_TYPE
+ ","
+ AnomalyColumns.ANOMALY_STATE
+ ","
+ AnomalyColumns.TIME_STAMP_MS
+ ")"
+ ")";
public interface ActionColumns {
/**
* The package name of an app been performed an action
*/
/** The package name of an app been performed an action */
String PACKAGE_NAME = "package_name";
/**
* The uid of an app been performed an action
*/
/** The uid of an app been performed an action */
String UID = "uid";
/**
* The type of user action
*
* @see ActionType
*/
String ACTION_TYPE = "action_type";
/**
* The time when action been performed
*/
/** The time when action been performed */
String TIME_STAMP_MS = "time_stamp_ms";
}
private static final String CREATE_ACTION_TABLE =
"CREATE TABLE " + Tables.TABLE_ACTION +
"(" +
ActionColumns.UID +
" INTEGER NOT NULL, " +
ActionColumns.PACKAGE_NAME +
" TEXT, " +
ActionColumns.ACTION_TYPE +
" INTEGER NOT NULL, " +
ActionColumns.TIME_STAMP_MS +
" INTEGER NOT NULL, " +
" PRIMARY KEY (" + ActionColumns.ACTION_TYPE + "," + ActionColumns.UID + ","
+ ActionColumns.PACKAGE_NAME + ")"
"CREATE TABLE "
+ Tables.TABLE_ACTION
+ "("
+ ActionColumns.UID
+ " INTEGER NOT NULL, "
+ ActionColumns.PACKAGE_NAME
+ " TEXT, "
+ ActionColumns.ACTION_TYPE
+ " INTEGER NOT NULL, "
+ ActionColumns.TIME_STAMP_MS
+ " INTEGER NOT NULL, "
+ " PRIMARY KEY ("
+ ActionColumns.ACTION_TYPE
+ ","
+ ActionColumns.UID
+ ","
+ ActionColumns.PACKAGE_NAME
+ ")"
+ ")";
private static AnomalyDatabaseHelper sSingleton;
@@ -155,8 +162,14 @@ public class AnomalyDatabaseHelper extends SQLiteOpenHelper {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < DATABASE_VERSION) {
Log.w(TAG, "Detected schema version '" + oldVersion + "'. " +
"Index needs to be rebuilt for schema version '" + newVersion + "'.");
Log.w(
TAG,
"Detected schema version '"
+ oldVersion
+ "'. "
+ "Index needs to be rebuilt for schema version '"
+ newVersion
+ "'.");
// We need to drop the tables and recreate them
reconstruct(db);
}
@@ -164,8 +177,14 @@ public class AnomalyDatabaseHelper extends SQLiteOpenHelper {
@Override
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Detected schema version '" + oldVersion + "'. " +
"Index needs to be rebuilt for schema version '" + newVersion + "'.");
Log.w(
TAG,
"Detected schema version '"
+ oldVersion
+ "'. "
+ "Index needs to be rebuilt for schema version '"
+ newVersion
+ "'.");
// We need to drop the tables and recreate them
reconstruct(db);
}

View File

@@ -57,22 +57,20 @@ import java.util.concurrent.TimeUnit;
public class AnomalyDetectionJobService extends JobService {
private static final String TAG = "AnomalyDetectionService";
private static final int ON = 1;
@VisibleForTesting
static final int UID_NULL = -1;
@VisibleForTesting
static final int STATSD_UID_FILED = 1;
@VisibleForTesting
static final long MAX_DELAY_MS = TimeUnit.MINUTES.toMillis(30);
@VisibleForTesting static final int UID_NULL = -1;
@VisibleForTesting static final int STATSD_UID_FILED = 1;
@VisibleForTesting static final long MAX_DELAY_MS = TimeUnit.MINUTES.toMillis(30);
private final Object mLock = new Object();
@GuardedBy("mLock")
@VisibleForTesting
boolean mIsJobCanceled = false;
public static void scheduleAnomalyDetection(Context context, Intent intent) {
final JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
final ComponentName component = new ComponentName(context,
AnomalyDetectionJobService.class);
final ComponentName component =
new ComponentName(context, AnomalyDetectionJobService.class);
final JobInfo.Builder jobBuilder =
new JobInfo.Builder(R.integer.job_anomaly_detection, component)
.setOverrideDeadline(MAX_DELAY_MS);
@@ -88,30 +86,40 @@ public class AnomalyDetectionJobService extends JobService {
synchronized (mLock) {
mIsJobCanceled = false;
}
ThreadUtils.postOnBackgroundThread(() -> {
final Context context = AnomalyDetectionJobService.this;
final BatteryDatabaseManager batteryDatabaseManager =
BatteryDatabaseManager.getInstance(this);
final BatteryTipPolicy policy = new BatteryTipPolicy(this);
final BatteryUtils batteryUtils = BatteryUtils.getInstance(this);
final ContentResolver contentResolver = getContentResolver();
final UserManager userManager = getSystemService(UserManager.class);
final PowerAllowlistBackend powerAllowlistBackend =
PowerAllowlistBackend.getInstance(context);
final PowerUsageFeatureProvider powerUsageFeatureProvider =
FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider();
final MetricsFeatureProvider metricsFeatureProvider =
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
ThreadUtils.postOnBackgroundThread(
() -> {
final Context context = AnomalyDetectionJobService.this;
final BatteryDatabaseManager batteryDatabaseManager =
BatteryDatabaseManager.getInstance(this);
final BatteryTipPolicy policy = new BatteryTipPolicy(this);
final BatteryUtils batteryUtils = BatteryUtils.getInstance(this);
final ContentResolver contentResolver = getContentResolver();
final UserManager userManager = getSystemService(UserManager.class);
final PowerAllowlistBackend powerAllowlistBackend =
PowerAllowlistBackend.getInstance(context);
final PowerUsageFeatureProvider powerUsageFeatureProvider =
FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider();
final MetricsFeatureProvider metricsFeatureProvider =
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
for (JobWorkItem item = dequeueWork(params); item != null; item = dequeueWork(params)) {
saveAnomalyToDatabase(context, userManager,
batteryDatabaseManager, batteryUtils, policy, powerAllowlistBackend,
contentResolver, powerUsageFeatureProvider, metricsFeatureProvider,
item.getIntent().getExtras());
for (JobWorkItem item = dequeueWork(params);
item != null;
item = dequeueWork(params)) {
saveAnomalyToDatabase(
context,
userManager,
batteryDatabaseManager,
batteryUtils,
policy,
powerAllowlistBackend,
contentResolver,
powerUsageFeatureProvider,
metricsFeatureProvider,
item.getIntent().getExtras());
completeWork(params, item);
}
});
completeWork(params, item);
}
});
return true;
}
@@ -125,34 +133,49 @@ public class AnomalyDetectionJobService extends JobService {
}
@VisibleForTesting
void saveAnomalyToDatabase(Context context, UserManager userManager,
BatteryDatabaseManager databaseManager, BatteryUtils batteryUtils,
BatteryTipPolicy policy, PowerAllowlistBackend powerAllowlistBackend,
ContentResolver contentResolver, PowerUsageFeatureProvider powerUsageFeatureProvider,
MetricsFeatureProvider metricsFeatureProvider, Bundle bundle) {
void saveAnomalyToDatabase(
Context context,
UserManager userManager,
BatteryDatabaseManager databaseManager,
BatteryUtils batteryUtils,
BatteryTipPolicy policy,
PowerAllowlistBackend powerAllowlistBackend,
ContentResolver contentResolver,
PowerUsageFeatureProvider powerUsageFeatureProvider,
MetricsFeatureProvider metricsFeatureProvider,
Bundle bundle) {
// The Example of intentDimsValue is: 35:{1:{1:{1:10013|}|}|}
final StatsDimensionsValue intentDimsValue =
bundle.getParcelable(StatsManager.EXTRA_STATS_DIMENSIONS_VALUE);
final long timeMs = bundle.getLong(AnomalyDetectionReceiver.KEY_ANOMALY_TIMESTAMP,
System.currentTimeMillis());
final ArrayList<String> cookies = bundle.getStringArrayList(
StatsManager.EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES);
final AnomalyInfo anomalyInfo = new AnomalyInfo(
!ArrayUtils.isEmpty(cookies) ? cookies.get(0) : "");
final long timeMs =
bundle.getLong(
AnomalyDetectionReceiver.KEY_ANOMALY_TIMESTAMP, System.currentTimeMillis());
final ArrayList<String> cookies =
bundle.getStringArrayList(StatsManager.EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES);
final AnomalyInfo anomalyInfo =
new AnomalyInfo(!ArrayUtils.isEmpty(cookies) ? cookies.get(0) : "");
Log.i(TAG, "Extra stats value: " + intentDimsValue.toString());
try {
final int uid = extractUidFromStatsDimensionsValue(intentDimsValue);
final boolean autoFeatureOn = powerUsageFeatureProvider.isSmartBatterySupported()
? Settings.Global.getInt(contentResolver,
Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, ON) == ON
: Settings.Global.getInt(contentResolver,
Settings.Global.APP_AUTO_RESTRICTION_ENABLED, ON) == ON;
final boolean autoFeatureOn =
powerUsageFeatureProvider.isSmartBatterySupported()
? Settings.Global.getInt(
contentResolver,
Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED,
ON)
== ON
: Settings.Global.getInt(
contentResolver,
Settings.Global.APP_AUTO_RESTRICTION_ENABLED,
ON)
== ON;
final String packageName = batteryUtils.getPackageName(uid);
final long versionCode = batteryUtils.getAppLongVersionCode(packageName);
final String versionedPackage = packageName + "/" + versionCode;
if (batteryUtils.shouldHideAnomaly(powerAllowlistBackend, uid, anomalyInfo)) {
metricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN,
metricsFeatureProvider.action(
SettingsEnums.PAGE_UNKNOWN,
SettingsEnums.ACTION_ANOMALY_IGNORED,
SettingsEnums.PAGE_UNKNOWN,
versionedPackage,
@@ -160,17 +183,23 @@ public class AnomalyDetectionJobService extends JobService {
} else {
if (autoFeatureOn && anomalyInfo.autoRestriction) {
// Auto restrict this app
batteryUtils.setForceAppStandby(uid, packageName,
AppOpsManager.MODE_IGNORED);
databaseManager.insertAnomaly(uid, packageName, anomalyInfo.anomalyType,
batteryUtils.setForceAppStandby(uid, packageName, AppOpsManager.MODE_IGNORED);
databaseManager.insertAnomaly(
uid,
packageName,
anomalyInfo.anomalyType,
AnomalyDatabaseHelper.State.AUTO_HANDLED,
timeMs);
} else {
databaseManager.insertAnomaly(uid, packageName, anomalyInfo.anomalyType,
databaseManager.insertAnomaly(
uid,
packageName,
anomalyInfo.anomalyType,
AnomalyDatabaseHelper.State.NEW,
timeMs);
}
metricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN,
metricsFeatureProvider.action(
SettingsEnums.PAGE_UNKNOWN,
SettingsEnums.ACTION_ANOMALY_TRIGGERED,
SettingsEnums.PAGE_UNKNOWN,
versionedPackage,
@@ -183,12 +212,12 @@ public class AnomalyDetectionJobService extends JobService {
}
/**
* Extract the uid from {@link StatsDimensionsValue}
*
* The uid dimension has the format: 1:<int> inside the tuple list. Here are some examples:
* 1. Excessive bg anomaly: 27:{1:10089|}
* 2. Wakeup alarm anomaly: 35:{1:{1:{1:10013|}|}|}
* 3. Bluetooth anomaly: 3:{1:{1:{1:10140|}|}|}
* Extract the uid from {@link StatsDimensionsValue} <br>
* <br>
* The uid dimension has the format: {1:int} inside the tuple list. Here are some examples: <br>
* 1.Excessive bg anomaly: 27:{1:10089|} <br>
* 2.Wakeup alarm anomaly: 35:{1:{1:{1:10013|}|}|} <br>
* 3.Bluetooth anomaly: 3:{1:{1:{1:10140|}|}|}
*/
@VisibleForTesting
int extractUidFromStatsDimensionsValue(StatsDimensionsValue statsDimensionsValue) {

View File

@@ -23,9 +23,7 @@ import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
/**
* Receive the anomaly info from {@link StatsManager}
*/
/** Receive the anomaly info from {@link StatsManager} */
public class AnomalyDetectionReceiver extends BroadcastReceiver {
private static final String TAG = "SettingsAnomalyReceiver";
@@ -35,10 +33,16 @@ public class AnomalyDetectionReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
final long configUid = intent.getLongExtra(StatsManager.EXTRA_STATS_CONFIG_UID, -1);
final long configKey = intent.getLongExtra(StatsManager.EXTRA_STATS_CONFIG_KEY, -1);
final long subscriptionId = intent.getLongExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID,
-1);
Log.i(TAG, "Anomaly intent received. configUid = " + configUid + " configKey = "
+ configKey + " subscriptionId = " + subscriptionId);
final long subscriptionId =
intent.getLongExtra(StatsManager.EXTRA_STATS_SUBSCRIPTION_ID, -1);
Log.i(
TAG,
"Anomaly intent received. configUid = "
+ configUid
+ " configKey = "
+ configKey
+ " subscriptionId = "
+ subscriptionId);
final Bundle bundle = intent.getExtras();
if (bundle == null) {

View File

@@ -19,9 +19,7 @@ package com.android.settings.fuelgauge.batterytip;
import android.util.KeyValueListParser;
import android.util.Log;
/**
* Model class to parse and store anomaly info from statsd.
*/
/** Model class to parse and store anomaly info from statsd. */
public class AnomalyInfo {
private static final String TAG = "AnomalyInfo";
@@ -37,5 +35,4 @@ public class AnomalyInfo {
anomalyType = parser.getInt(KEY_ANOMALY_TYPE, -1);
autoRestriction = parser.getBoolean(KEY_AUTO_RESTRICTION, false);
}
}

View File

@@ -25,16 +25,17 @@ import androidx.annotation.VisibleForTesting;
import java.util.Objects;
/**
* Model class stores app info(e.g. package name, type..) that used in battery tip
*/
/** Model class stores app info(e.g. package name, type..) that used in battery tip */
public class AppInfo implements Comparable<AppInfo>, Parcelable {
public final String packageName;
/**
* Anomaly type of the app
*
* @see StatsManagerConfig.AnomalyType
*/
public final ArraySet<Integer> anomalyTypes;
public final long screenOnTimeMs;
public final int uid;
@@ -73,7 +74,11 @@ public class AppInfo implements Comparable<AppInfo>, Parcelable {
@Override
public String toString() {
return "packageName=" + packageName + ",anomalyTypes=" + anomalyTypes + ",screenTime="
return "packageName="
+ packageName
+ ",anomalyTypes="
+ anomalyTypes
+ ",screenTime="
+ screenOnTimeMs;
}
@@ -93,15 +98,16 @@ public class AppInfo implements Comparable<AppInfo>, Parcelable {
&& TextUtils.equals(packageName, other.packageName);
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public AppInfo createFromParcel(Parcel in) {
return new AppInfo(in);
}
public static final Parcelable.Creator CREATOR =
new Parcelable.Creator() {
public AppInfo createFromParcel(Parcel in) {
return new AppInfo(in);
}
public AppInfo[] newArray(int size) {
return new AppInfo[size];
}
};
public AppInfo[] newArray(int size) {
return new AppInfo[size];
}
};
public static final class Builder {
private ArraySet<Integer> mAnomalyTypes = new ArraySet<>();

View File

@@ -47,8 +47,8 @@ import java.util.Map;
/**
* Database manager for battery data. Now it only contains anomaly data stored in {@link AppInfo}.
*
* This manager may be accessed by multi-threads. All the database related methods are synchronized
* so each operation won't be interfered by other threads.
* <p>This manager may be accessed by multi-threads. All the database related methods are
* synchronized so each operation won't be interfered by other threads.
*/
public class BatteryDatabaseManager {
private static BatteryDatabaseManager sSingleton;
@@ -74,16 +74,15 @@ public class BatteryDatabaseManager {
/**
* Insert an anomaly log to database.
*
* @param uid the uid of the app
* @param packageName the package name of the app
* @param type the type of the anomaly
* @param uid the uid of the app
* @param packageName the package name of the app
* @param type the type of the anomaly
* @param anomalyState the state of the anomaly
* @param timestampMs the time when it is happened
* @param timestampMs the time when it is happened
* @return {@code true} if insert operation succeed
*/
public synchronized boolean insertAnomaly(int uid, String packageName, int type,
int anomalyState,
long timestampMs) {
public synchronized boolean insertAnomaly(
int uid, String packageName, int type, int anomalyState, long timestampMs) {
final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(UID, uid);
@@ -105,22 +104,31 @@ public class BatteryDatabaseManager {
final String orderBy = AnomalyDatabaseHelper.AnomalyColumns.TIME_STAMP_MS + " DESC";
final Map<Integer, AppInfo.Builder> mAppInfoBuilders = new ArrayMap<>();
final String selection = TIME_STAMP_MS + " > ? AND " + ANOMALY_STATE + " = ? ";
final String[] selectionArgs = new String[]{String.valueOf(timestampMsAfter),
String.valueOf(state)};
final String[] selectionArgs =
new String[] {String.valueOf(timestampMsAfter), String.valueOf(state)};
try (Cursor cursor = db.query(TABLE_ANOMALY, projection, selection, selectionArgs,
null /* groupBy */, null /* having */, orderBy)) {
try (Cursor cursor =
db.query(
TABLE_ANOMALY,
projection,
selection,
selectionArgs,
null /* groupBy */,
null /* having */,
orderBy)) {
while (cursor.moveToNext()) {
final int uid = cursor.getInt(cursor.getColumnIndex(UID));
if (!mAppInfoBuilders.containsKey(uid)) {
final AppInfo.Builder builder = new AppInfo.Builder()
.setUid(uid)
.setPackageName(
cursor.getString(cursor.getColumnIndex(PACKAGE_NAME)));
final AppInfo.Builder builder =
new AppInfo.Builder()
.setUid(uid)
.setPackageName(
cursor.getString(cursor.getColumnIndex(PACKAGE_NAME)));
mAppInfoBuilders.put(uid, builder);
}
mAppInfoBuilders.get(uid).addAnomalyType(
cursor.getInt(cursor.getColumnIndex(ANOMALY_TYPE)));
mAppInfoBuilders
.get(uid)
.addAnomalyType(cursor.getInt(cursor.getColumnIndex(ANOMALY_TYPE)));
}
}
@@ -133,15 +141,15 @@ public class BatteryDatabaseManager {
public synchronized void deleteAllAnomaliesBeforeTimeStamp(long timestampMs) {
final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
db.delete(TABLE_ANOMALY, TIME_STAMP_MS + " < ?",
new String[]{String.valueOf(timestampMs)});
db.delete(
TABLE_ANOMALY, TIME_STAMP_MS + " < ?", new String[] {String.valueOf(timestampMs)});
}
/**
* Update the type of anomalies to {@code state}
*
* @param appInfos represents the anomalies
* @param state which state to update to
* @param state which state to update to
*/
public synchronized void updateAnomalies(List<AppInfo> appInfos, int state) {
if (!appInfos.isEmpty()) {
@@ -154,8 +162,14 @@ public class BatteryDatabaseManager {
final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
final ContentValues values = new ContentValues();
values.put(ANOMALY_STATE, state);
db.update(TABLE_ANOMALY, values, PACKAGE_NAME + " IN (" + TextUtils.join(",",
Collections.nCopies(appInfos.size(), "?")) + ")", whereArgs);
db.update(
TABLE_ANOMALY,
values,
PACKAGE_NAME
+ " IN ("
+ TextUtils.join(",", Collections.nCopies(appInfos.size(), "?"))
+ ")",
whereArgs);
}
}
@@ -171,10 +185,17 @@ public class BatteryDatabaseManager {
final SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
final String[] projection = {ActionColumns.UID, ActionColumns.TIME_STAMP_MS};
final String selection = ActionColumns.ACTION_TYPE + " = ? ";
final String[] selectionArgs = new String[]{String.valueOf(type)};
final String[] selectionArgs = new String[] {String.valueOf(type)};
try (Cursor cursor = db.query(TABLE_ACTION, projection, selection, selectionArgs,
null /* groupBy */, null /* having */, null /* orderBy */)) {
try (Cursor cursor =
db.query(
TABLE_ACTION,
projection,
selection,
selectionArgs,
null /* groupBy */,
null /* having */,
null /* orderBy */)) {
final int uidIndex = cursor.getColumnIndex(ActionColumns.UID);
final int timestampIndex = cursor.getColumnIndex(ActionColumns.TIME_STAMP_MS);
@@ -188,11 +209,12 @@ public class BatteryDatabaseManager {
return timeStamps;
}
/**
* Insert an action, or update it if already existed
*/
public synchronized boolean insertAction(@AnomalyDatabaseHelper.ActionType int type,
int uid, String packageName, long timestampMs) {
/** Insert an action, or update it if already existed */
public synchronized boolean insertAction(
@AnomalyDatabaseHelper.ActionType int type,
int uid,
String packageName,
long timestampMs) {
final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
final ContentValues values = new ContentValues();
values.put(ActionColumns.UID, uid);
@@ -203,17 +225,21 @@ public class BatteryDatabaseManager {
return db.insertWithOnConflict(TABLE_ACTION, null, values, CONFLICT_REPLACE) != -1;
}
/**
* Remove an action
*/
public synchronized boolean deleteAction(@AnomalyDatabaseHelper.ActionType int type,
int uid, String packageName) {
/** Remove an action */
public synchronized boolean deleteAction(
@AnomalyDatabaseHelper.ActionType int type, int uid, String packageName) {
SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
final String where =
ActionColumns.ACTION_TYPE + " = ? AND " + ActionColumns.UID + " = ? AND "
+ ActionColumns.PACKAGE_NAME + " = ? ";
final String[] whereArgs = new String[]{String.valueOf(type), String.valueOf(uid),
String.valueOf(packageName)};
ActionColumns.ACTION_TYPE
+ " = ? AND "
+ ActionColumns.UID
+ " = ? AND "
+ ActionColumns.PACKAGE_NAME
+ " = ? ";
final String[] whereArgs =
new String[] {
String.valueOf(type), String.valueOf(uid), String.valueOf(packageName)
};
return db.delete(TABLE_ACTION, where, whereArgs) != 0;
}

View File

@@ -46,19 +46,15 @@ import com.android.settingslib.utils.StringUtil;
import java.util.List;
/**
* Dialog Fragment to show action dialog for each anomaly
*/
public class BatteryTipDialogFragment extends InstrumentedDialogFragment implements
DialogInterface.OnClickListener {
/** Dialog Fragment to show action dialog for each anomaly */
public class BatteryTipDialogFragment extends InstrumentedDialogFragment
implements DialogInterface.OnClickListener {
private static final String ARG_BATTERY_TIP = "battery_tip";
private static final String ARG_METRICS_KEY = "metrics_key";
@VisibleForTesting
BatteryTip mBatteryTip;
@VisibleForTesting
int mMetricsKey;
@VisibleForTesting BatteryTip mBatteryTip;
@VisibleForTesting int mMetricsKey;
public static BatteryTipDialogFragment newInstance(BatteryTip batteryTip, int metricsKey) {
BatteryTipDialogFragment dialogFragment = new BatteryTipDialogFragment();
@@ -87,16 +83,17 @@ public class BatteryTipDialogFragment extends InstrumentedDialogFragment impleme
.create();
case BatteryTip.TipType.HIGH_DEVICE_USAGE:
final HighUsageTip highUsageTip = (HighUsageTip) mBatteryTip;
final RecyclerView view = (RecyclerView) LayoutInflater.from(context).inflate(
R.layout.recycler_view,
null);
final RecyclerView view =
(RecyclerView)
LayoutInflater.from(context).inflate(R.layout.recycler_view, null);
view.setLayoutManager(new LinearLayoutManager(context));
view.setAdapter(new HighUsageAdapter(context,
highUsageTip.getHighUsageAppList()));
view.setAdapter(new HighUsageAdapter(context, highUsageTip.getHighUsageAppList()));
return new AlertDialog.Builder(context)
.setMessage(getString(R.string.battery_tip_dialog_message,
highUsageTip.getHighUsageAppList().size()))
.setMessage(
getString(
R.string.battery_tip_dialog_message,
highUsageTip.getHighUsageAppList().size()))
.setView(view)
.setPositiveButton(android.R.string.ok, null)
.create();
@@ -104,14 +101,19 @@ public class BatteryTipDialogFragment extends InstrumentedDialogFragment impleme
final RestrictAppTip restrictAppTip = (RestrictAppTip) mBatteryTip;
final List<AppInfo> restrictedAppList = restrictAppTip.getRestrictAppList();
final int num = restrictedAppList.size();
final CharSequence appLabel = Utils.getApplicationLabel(context,
restrictedAppList.get(0).packageName);
final CharSequence appLabel =
Utils.getApplicationLabel(context, restrictedAppList.get(0).packageName);
final AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setTitle(StringUtil.getIcuPluralsString(context, num,
R.string.battery_tip_restrict_app_dialog_title))
.setPositiveButton(R.string.battery_tip_restrict_app_dialog_ok, this)
.setNegativeButton(android.R.string.cancel, null);
final AlertDialog.Builder builder =
new AlertDialog.Builder(context)
.setTitle(
StringUtil.getIcuPluralsString(
context,
num,
R.string.battery_tip_restrict_app_dialog_title))
.setPositiveButton(
R.string.battery_tip_restrict_app_dialog_ok, this)
.setNegativeButton(android.R.string.cancel, null);
if (num == 1) {
builder.setMessage(
getString(R.string.battery_tip_restrict_app_dialog_message, appLabel));
@@ -119,22 +121,25 @@ public class BatteryTipDialogFragment extends InstrumentedDialogFragment impleme
builder.setMessage(
getString(
R.string.battery_tip_restrict_apps_less_than_5_dialog_message));
final RecyclerView restrictionView = (RecyclerView) LayoutInflater.from(
context).inflate(R.layout.recycler_view, null);
final RecyclerView restrictionView =
(RecyclerView)
LayoutInflater.from(context)
.inflate(R.layout.recycler_view, null);
restrictionView.setLayoutManager(new LinearLayoutManager(context));
restrictionView.setAdapter(new HighUsageAdapter(context, restrictedAppList));
builder.setView(restrictionView);
} else {
builder.setMessage(context.getString(
R.string.battery_tip_restrict_apps_more_than_5_dialog_message,
restrictAppTip.getRestrictAppsString(context)));
builder.setMessage(
context.getString(
R.string.battery_tip_restrict_apps_more_than_5_dialog_message,
restrictAppTip.getRestrictAppsString(context)));
}
return builder.create();
case BatteryTip.TipType.REMOVE_APP_RESTRICTION:
final UnrestrictAppTip unrestrictAppTip = (UnrestrictAppTip) mBatteryTip;
final CharSequence name = Utils.getApplicationLabel(context,
unrestrictAppTip.getPackageName());
final CharSequence name =
Utils.getApplicationLabel(context, unrestrictAppTip.getPackageName());
return new AlertDialog.Builder(context)
.setTitle(getString(R.string.battery_tip_unrestrict_app_dialog_title))
@@ -158,9 +163,11 @@ public class BatteryTipDialogFragment extends InstrumentedDialogFragment impleme
if (lsn == null) {
return;
}
final BatteryTipAction action = BatteryTipUtils.getActionForBatteryTip(mBatteryTip,
(SettingsActivity) getActivity(),
(InstrumentedPreferenceFragment) getTargetFragment());
final BatteryTipAction action =
BatteryTipUtils.getActionForBatteryTip(
mBatteryTip,
(SettingsActivity) getActivity(),
(InstrumentedPreferenceFragment) getTargetFragment());
if (action != null) {
action.handlePositiveAction(mMetricsKey);
}
@@ -168,10 +175,12 @@ public class BatteryTipDialogFragment extends InstrumentedDialogFragment impleme
}
private boolean isPluggedIn() {
final Intent batteryIntent = getContext().registerReceiver(null /* receiver */,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
return batteryIntent != null && batteryIntent.getIntExtra(
BatteryManager.EXTRA_PLUGGED, 0) != 0;
final Intent batteryIntent =
getContext()
.registerReceiver(
null /* receiver */,
new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
return batteryIntent != null
&& batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
}
}

View File

@@ -29,10 +29,7 @@ import com.android.settings.fuelgauge.batterytip.detectors.DockDefenderDetector;
import com.android.settings.fuelgauge.batterytip.detectors.HighUsageDetector;
import com.android.settings.fuelgauge.batterytip.detectors.IncompatibleChargerDetector;
import com.android.settings.fuelgauge.batterytip.detectors.LowBatteryDetector;
import com.android.settings.fuelgauge.batterytip.detectors.SmartBatteryDetector;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip;
import com.android.settingslib.fuelgauge.EstimateKt;
import com.android.settingslib.utils.AsyncLoaderCompat;
import java.util.ArrayList;
@@ -47,8 +44,7 @@ public class BatteryTipLoader extends AsyncLoaderCompat<List<BatteryTip>> {
private static final String TAG = "BatteryTipLoader";
private BatteryUsageStats mBatteryUsageStats;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@VisibleForTesting BatteryUtils mBatteryUtils;
public BatteryTipLoader(Context context, BatteryUsageStats batteryUsageStats) {
super(context);
@@ -75,6 +71,5 @@ public class BatteryTipLoader extends AsyncLoaderCompat<List<BatteryTip>> {
}
@Override
protected void onDiscardResult(List<BatteryTip> result) {
}
protected void onDiscardResult(List<BatteryTip> result) {}
}

View File

@@ -25,10 +25,7 @@ import androidx.annotation.VisibleForTesting;
import java.time.Duration;
/**
* Class to store the policy for battery tips, which comes from
* {@link Settings.Global}
*/
/** Class to store the policy for battery tips, which comes from {@link Settings.Global} */
public class BatteryTipPolicy {
public static final String TAG = "BatteryTipPolicy";
@@ -102,9 +99,9 @@ public class BatteryTipPolicy {
public final long highUsagePeriodMs;
/**
* The battery draining threshold to detect whether device is heavily used.
* If battery drains more than {@link #highUsageBatteryDraining} in last {@link
* #highUsagePeriodMs}, treat device as heavily used.
* The battery draining threshold to detect whether device is heavily used. If battery drains
* more than {@link #highUsageBatteryDraining} in last {@link #highUsagePeriodMs}, treat device
* as heavily used.
*
* @see Settings.Global#BATTERY_TIP_CONSTANTS
* @see #KEY_HIGH_USAGE_BATTERY_DRAINING
@@ -171,8 +168,8 @@ public class BatteryTipPolicy {
/**
* Battery drain percentage threshold for excessive background anomaly(i.e. 10%)
*
* This is an additional check for excessive background, to check whether battery drain
* for an app is larger than x%
* <p>This is an additional check for excessive background, to check whether battery drain for
* an app is larger than x%
*
* @see Settings.Global#BATTERY_TIP_CONSTANTS
* @see #KEY_EXCESSIVE_BG_DRAIN_PERCENTAGE
@@ -220,8 +217,9 @@ public class BatteryTipPolicy {
@VisibleForTesting
BatteryTipPolicy(Context context, KeyValueListParser parser) {
mParser = parser;
final String value = Settings.Global.getString(context.getContentResolver(),
Settings.Global.BATTERY_TIP_CONSTANTS);
final String value =
Settings.Global.getString(
context.getContentResolver(), Settings.Global.BATTERY_TIP_CONSTANTS);
try {
mParser.setString(value);
@@ -234,8 +232,8 @@ public class BatteryTipPolicy {
batterySaverTipEnabled = mParser.getBoolean(KEY_BATTERY_SAVER_TIP_ENABLED, true);
highUsageEnabled = mParser.getBoolean(KEY_HIGH_USAGE_ENABLED, true);
highUsageAppCount = mParser.getInt(KEY_HIGH_USAGE_APP_COUNT, 3);
highUsagePeriodMs = mParser.getLong(KEY_HIGH_USAGE_PERIOD_MS,
Duration.ofHours(2).toMillis());
highUsagePeriodMs =
mParser.getLong(KEY_HIGH_USAGE_PERIOD_MS, Duration.ofHours(2).toMillis());
highUsageBatteryDraining = mParser.getInt(KEY_HIGH_USAGE_BATTERY_DRAINING, 25);
appRestrictionEnabled = mParser.getBoolean(KEY_APP_RESTRICTION_ENABLED, true);
appRestrictionActiveHour = mParser.getInt(KEY_APP_RESTRICTION_ACTIVE_HOUR, 24);
@@ -251,5 +249,4 @@ public class BatteryTipPolicy {
testSmartBatteryTip = mParser.getBoolean(KEY_TEST_SMART_BATTERY_TIP, false);
testLowBatteryTip = mParser.getBoolean(KEY_TEST_LOW_BATTERY_TIP, false);
}
}

View File

@@ -40,9 +40,7 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* Controller in charge of the battery tip group
*/
/** Controller in charge of the battery tip group */
public class BatteryTipPreferenceController extends BasePreferenceController {
public static final String PREF_NAME = "battery_tip";
@@ -57,10 +55,8 @@ public class BatteryTipPreferenceController extends BasePreferenceController {
private SettingsActivity mSettingsActivity;
private MetricsFeatureProvider mMetricsFeatureProvider;
private boolean mNeedUpdate;
@VisibleForTesting
CardPreference mCardPreference;
@VisibleForTesting
Context mPrefContext;
@VisibleForTesting CardPreference mCardPreference;
@VisibleForTesting Context mPrefContext;
InstrumentedPreferenceFragment mFragment;
public BatteryTipPreferenceController(Context context, String preferenceKey) {
@@ -122,13 +118,15 @@ public class BatteryTipPreferenceController extends BasePreferenceController {
final BatteryTip batteryTip = mBatteryTipMap.get(preference.getKey());
if (batteryTip != null) {
if (batteryTip.shouldShowDialog()) {
BatteryTipDialogFragment dialogFragment = BatteryTipDialogFragment.newInstance(
batteryTip, mFragment.getMetricsCategory());
BatteryTipDialogFragment dialogFragment =
BatteryTipDialogFragment.newInstance(
batteryTip, mFragment.getMetricsCategory());
dialogFragment.setTargetFragment(mFragment, REQUEST_ANOMALY_ACTION);
dialogFragment.show(mFragment.getFragmentManager(), TAG);
} else {
final BatteryTipAction action = BatteryTipUtils.getActionForBatteryTip(batteryTip,
mSettingsActivity, mFragment);
final BatteryTipAction action =
BatteryTipUtils.getActionForBatteryTip(
batteryTip, mSettingsActivity, mFragment);
if (action != null) {
action.handlePositiveAction(mFragment.getMetricsCategory());
}
@@ -183,13 +181,11 @@ public class BatteryTipPreferenceController extends BasePreferenceController {
return visibleBatteryTip.orElse(null);
}
/**
* Listener to give the control back to target fragment
*/
/** Listener to give the control back to target fragment */
public interface BatteryTipListener {
/**
* This method is invoked once battery tip is handled, then target fragment could do
* extra work.
* This method is invoked once battery tip is handled, then target fragment could do extra
* work.
*
* @param batteryTip that has been handled
*/

View File

@@ -48,15 +48,13 @@ import java.util.List;
public class BatteryTipUtils {
private static final int REQUEST_CODE = 0;
/**
* Get a list of restricted apps with {@link AppOpsManager#OP_RUN_ANY_IN_BACKGROUND}
*/
/** Get a list of restricted apps with {@link AppOpsManager#OP_RUN_ANY_IN_BACKGROUND} */
@NonNull
public static List<AppInfo> getRestrictedAppsList(AppOpsManager appOpsManager,
UserManager userManager) {
public static List<AppInfo> getRestrictedAppsList(
AppOpsManager appOpsManager, UserManager userManager) {
final List<UserHandle> userHandles = userManager.getUserProfiles();
final List<AppOpsManager.PackageOps> packageOpsList = appOpsManager.getPackagesForOps(
new int[]{AppOpsManager.OP_RUN_ANY_IN_BACKGROUND});
final List<AppOpsManager.PackageOps> packageOpsList =
appOpsManager.getPackagesForOps(new int[] {AppOpsManager.OP_RUN_ANY_IN_BACKGROUND});
final List<AppInfo> appInfos = new ArrayList<>();
for (int i = 0, size = CollectionUtils.size(packageOpsList); i < size; i++) {
@@ -69,11 +67,12 @@ public class BatteryTipUtils {
}
if (entry.getMode() != AppOpsManager.MODE_ALLOWED
&& userHandles.contains(
new UserHandle(UserHandle.getUserId(packageOps.getUid())))) {
appInfos.add(new AppInfo.Builder()
.setPackageName(packageOps.getPackageName())
.setUid(packageOps.getUid())
.build());
new UserHandle(UserHandle.getUserId(packageOps.getUid())))) {
appInfos.add(
new AppInfo.Builder()
.setPackageName(packageOps.getPackageName())
.setUid(packageOps.getUid())
.build());
}
}
}
@@ -89,8 +88,10 @@ public class BatteryTipUtils {
* @param fragment used to populate {@link BatteryTipAction}
* @return an action for {@code batteryTip}
*/
public static BatteryTipAction getActionForBatteryTip(BatteryTip batteryTip,
SettingsActivity settingsActivity, InstrumentedPreferenceFragment fragment) {
public static BatteryTipAction getActionForBatteryTip(
BatteryTip batteryTip,
SettingsActivity settingsActivity,
InstrumentedPreferenceFragment fragment) {
switch (batteryTip.getType()) {
case BatteryTip.TipType.SMART_BATTERY_MANAGER:
return new SmartBatteryAction(settingsActivity, fragment);
@@ -112,26 +113,33 @@ public class BatteryTipUtils {
/**
* Upload the {@link PendingIntent} to {@link StatsManager} for anomaly detection
*
* @throws StatsManager.StatsUnavailableException if failed to communicate with stats service
*/
public static void uploadAnomalyPendingIntent(Context context, StatsManager statsManager)
throws StatsManager.StatsUnavailableException {
final Intent extraIntent = new Intent(context, AnomalyDetectionReceiver.class);
final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, REQUEST_CODE,
extraIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
statsManager.setBroadcastSubscriber(pendingIntent,
StatsManagerConfig.ANOMALY_CONFIG_KEY, StatsManagerConfig.SUBSCRIBER_ID);
final PendingIntent pendingIntent =
PendingIntent.getBroadcast(
context,
REQUEST_CODE,
extraIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
statsManager.setBroadcastSubscriber(
pendingIntent,
StatsManagerConfig.ANOMALY_CONFIG_KEY,
StatsManagerConfig.SUBSCRIBER_ID);
}
/**
* Detect and return anomaly apps after {@code timeAfterMs}
*/
/** Detect and return anomaly apps after {@code timeAfterMs} */
public static List<AppInfo> detectAnomalies(Context context, long timeAfterMs) {
final List<AppInfo> highUsageApps = BatteryDatabaseManager.getInstance(context)
.queryAllAnomalies(timeAfterMs, AnomalyDatabaseHelper.State.NEW);
final List<AppInfo> highUsageApps =
BatteryDatabaseManager.getInstance(context)
.queryAllAnomalies(timeAfterMs, AnomalyDatabaseHelper.State.NEW);
// Remove it if it doesn't have label or been restricted
highUsageApps.removeIf(AppLabelPredicate.getInstance(context)
.or(AppRestrictionPredicate.getInstance(context)));
highUsageApps.removeIf(
AppLabelPredicate.getInstance(context)
.or(AppRestrictionPredicate.getInstance(context)));
return highUsageApps;
}

View File

@@ -33,9 +33,7 @@ import com.android.settings.Utils;
import java.util.List;
/**
* Adapter for the high usage app list
*/
/** Adapter for the high usage app list */
public class HighUsageAdapter extends RecyclerView.Adapter<HighUsageAdapter.ViewHolder> {
private final Context mContext;
private final IconDrawableFactory mIconDrawableFactory;
@@ -66,8 +64,8 @@ public class HighUsageAdapter extends RecyclerView.Adapter<HighUsageAdapter.View
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(mContext).inflate(R.layout.app_high_usage_item,
parent, false);
final View view =
LayoutInflater.from(mContext).inflate(R.layout.app_high_usage_item, parent, false);
return new ViewHolder(view);
}
@@ -75,7 +73,10 @@ public class HighUsageAdapter extends RecyclerView.Adapter<HighUsageAdapter.View
public void onBindViewHolder(ViewHolder holder, int position) {
final AppInfo app = mHighUsageAppList.get(position);
holder.appIcon.setImageDrawable(
Utils.getBadgedIcon(mIconDrawableFactory, mPackageManager, app.packageName,
Utils.getBadgedIcon(
mIconDrawableFactory,
mPackageManager,
app.packageName,
UserHandle.getUserId(app.uid)));
CharSequence label = Utils.getApplicationLabel(mContext, app.packageName);
if (label == null) {

View File

@@ -20,20 +20,17 @@ import android.os.BatteryStats;
import com.android.settings.fuelgauge.BatteryInfo;
/**
* DataParser used to go through battery data and detect whether battery is
* heavily used.
*/
/** DataParser used to go through battery data and detect whether battery is heavily used. */
public class HighUsageDataParser implements BatteryInfo.BatteryDataParser {
/**
* time period to check the battery usage
*/
/** Time period to check the battery usage */
private final long mTimePeriodMs;
/**
* treat device as heavily used if battery usage is more than {@code threshold}. 1 means 1%
* Treat device as heavily used if battery usage is more than {@code threshold}. 1 means 1%
* battery usage.
*/
private int mThreshold;
private long mEndTimeMs;
private byte mEndBatteryLevel;
private byte mLastPeriodBatteryLevel;
@@ -69,11 +66,8 @@ public class HighUsageDataParser implements BatteryInfo.BatteryDataParser {
mBatteryDrain = mLastPeriodBatteryLevel - mEndBatteryLevel;
}
/**
* Return {@code true} if the battery drain in {@link #mTimePeriodMs} is too much
*/
/** Return {@code true} if the battery drain in {@link #mTimePeriodMs} is too much */
public boolean isDeviceHeavilyUsed() {
return mBatteryDrain > mThreshold;
}
}

View File

@@ -21,244 +21,197 @@ import androidx.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* This class provides all the configs needed if we want to use {@link android.app.StatsManager}
*/
/** This class provides all the configs needed if we want to use {@link android.app.StatsManager} */
public class StatsManagerConfig {
/**
* The key that represents the anomaly config.
* This value is used in {@link android.app.StatsManager#addConfig(long, byte[])}
* The key that represents the anomaly config. This value is used in {@link
* android.app.StatsManager#addConfig(long, byte[])}
*/
public static final long ANOMALY_CONFIG_KEY = 1;
/**
* The key that represents subscriber, which is settings app.
*/
/** The key that represents subscriber, which is settings app. */
public static final long SUBSCRIBER_ID = 1;
@Retention(RetentionPolicy.SOURCE)
@IntDef({AnomalyType.NULL,
AnomalyType.UNKNOWN_REASON,
AnomalyType.EXCESSIVE_WAKELOCK_ALL_SCREEN_OFF,
AnomalyType.EXCESSIVE_WAKEUPS_IN_BACKGROUND,
AnomalyType.EXCESSIVE_UNOPTIMIZED_BLE_SCAN,
AnomalyType.EXCESSIVE_BACKGROUND_SERVICE,
AnomalyType.EXCESSIVE_WIFI_SCAN,
AnomalyType.EXCESSIVE_FLASH_WRITES,
AnomalyType.EXCESSIVE_MEMORY_IN_BACKGROUND,
AnomalyType.EXCESSIVE_DAVEY_RATE,
AnomalyType.EXCESSIVE_JANKY_FRAMES,
AnomalyType.SLOW_COLD_START_TIME,
AnomalyType.SLOW_HOT_START_TIME,
AnomalyType.SLOW_WARM_START_TIME,
AnomalyType.EXCESSIVE_BACKGROUND_SYNCS,
AnomalyType.EXCESSIVE_GPS_SCANS_IN_BACKGROUND,
AnomalyType.EXCESSIVE_JOB_SCHEDULING,
AnomalyType.EXCESSIVE_MOBILE_NETWORK_IN_BACKGROUND,
AnomalyType.EXCESSIVE_WIFI_LOCK_TIME,
AnomalyType.JOB_TIMED_OUT,
AnomalyType.LONG_UNOPTIMIZED_BLE_SCAN,
AnomalyType.BACKGROUND_ANR,
AnomalyType.BACKGROUND_CRASH_RATE,
AnomalyType.EXCESSIVE_ANR_LOOPING,
AnomalyType.EXCESSIVE_ANRS,
AnomalyType.EXCESSIVE_CRASH_RATE,
AnomalyType.EXCESSIVE_CRASH_LOOPING,
AnomalyType.NUMBER_OF_OPEN_FILES,
AnomalyType.EXCESSIVE_CAMERA_USAGE_IN_BACKGROUND,
AnomalyType.EXCESSIVE_CONTACT_ACCESS,
AnomalyType.EXCESSIVE_AUDIO_IN_BACKGROUND,
AnomalyType.EXCESSIVE_CRASH_ANR_IN_BACKGROUND,
AnomalyType.BATTERY_DRAIN_FROM_UNUSED_APP,
@IntDef({
AnomalyType.NULL,
AnomalyType.UNKNOWN_REASON,
AnomalyType.EXCESSIVE_WAKELOCK_ALL_SCREEN_OFF,
AnomalyType.EXCESSIVE_WAKEUPS_IN_BACKGROUND,
AnomalyType.EXCESSIVE_UNOPTIMIZED_BLE_SCAN,
AnomalyType.EXCESSIVE_BACKGROUND_SERVICE,
AnomalyType.EXCESSIVE_WIFI_SCAN,
AnomalyType.EXCESSIVE_FLASH_WRITES,
AnomalyType.EXCESSIVE_MEMORY_IN_BACKGROUND,
AnomalyType.EXCESSIVE_DAVEY_RATE,
AnomalyType.EXCESSIVE_JANKY_FRAMES,
AnomalyType.SLOW_COLD_START_TIME,
AnomalyType.SLOW_HOT_START_TIME,
AnomalyType.SLOW_WARM_START_TIME,
AnomalyType.EXCESSIVE_BACKGROUND_SYNCS,
AnomalyType.EXCESSIVE_GPS_SCANS_IN_BACKGROUND,
AnomalyType.EXCESSIVE_JOB_SCHEDULING,
AnomalyType.EXCESSIVE_MOBILE_NETWORK_IN_BACKGROUND,
AnomalyType.EXCESSIVE_WIFI_LOCK_TIME,
AnomalyType.JOB_TIMED_OUT,
AnomalyType.LONG_UNOPTIMIZED_BLE_SCAN,
AnomalyType.BACKGROUND_ANR,
AnomalyType.BACKGROUND_CRASH_RATE,
AnomalyType.EXCESSIVE_ANR_LOOPING,
AnomalyType.EXCESSIVE_ANRS,
AnomalyType.EXCESSIVE_CRASH_RATE,
AnomalyType.EXCESSIVE_CRASH_LOOPING,
AnomalyType.NUMBER_OF_OPEN_FILES,
AnomalyType.EXCESSIVE_CAMERA_USAGE_IN_BACKGROUND,
AnomalyType.EXCESSIVE_CONTACT_ACCESS,
AnomalyType.EXCESSIVE_AUDIO_IN_BACKGROUND,
AnomalyType.EXCESSIVE_CRASH_ANR_IN_BACKGROUND,
AnomalyType.BATTERY_DRAIN_FROM_UNUSED_APP,
})
public @interface AnomalyType {
/**
* This represents an error condition in the anomaly detection.
*/
/** This represents an error condition in the anomaly detection. */
int NULL = -1;
/**
* The anomaly type does not match any other defined type.
*/
/** The anomaly type does not match any other defined type. */
int UNKNOWN_REASON = 0;
/**
* The application held a partial (screen off) wake lock for a period of time that
* exceeded the threshold with the screen off when not charging.
* The application held a partial (screen off) wake lock for a period of time that exceeded
* the threshold with the screen off when not charging.
*/
int EXCESSIVE_WAKELOCK_ALL_SCREEN_OFF = 1;
/**
* The application exceeded the maximum number of wakeups while in the background
* when not charging.
* The application exceeded the maximum number of wakeups while in the background when not
* charging.
*/
int EXCESSIVE_WAKEUPS_IN_BACKGROUND = 2;
/**
* The application did unoptimized Bluetooth scans too frequently when not charging.
*/
/** The application did unoptimized Bluetooth scans too frequently when not charging. */
int EXCESSIVE_UNOPTIMIZED_BLE_SCAN = 3;
/**
* The application ran in the background for a period of time that exceeded the
* threshold.
* The application ran in the background for a period of time that exceeded the threshold.
*/
int EXCESSIVE_BACKGROUND_SERVICE = 4;
/**
* The application exceeded the maximum number of wifi scans when not charging.
*/
/** The application exceeded the maximum number of wifi scans when not charging. */
int EXCESSIVE_WIFI_SCAN = 5;
/**
* The application exceed the maximum number of flash writes
*/
/** The application exceed the maximum number of flash writes */
int EXCESSIVE_FLASH_WRITES = 6;
/**
* The application used more than the maximum memory, while not spending any time
* in the foreground.
* The application used more than the maximum memory, while not spending any time in the
* foreground.
*/
int EXCESSIVE_MEMORY_IN_BACKGROUND = 7;
/**
* The application exceeded the maximum percentage of frames with a render rate of
* greater than 700ms.
* The application exceeded the maximum percentage of frames with a render rate of greater
* than 700ms.
*/
int EXCESSIVE_DAVEY_RATE = 8;
/**
* The application exceeded the maximum percentage of frames with a render rate
* greater than 16ms.
* The application exceeded the maximum percentage of frames with a render rate greater than
* 16ms.
*/
int EXCESSIVE_JANKY_FRAMES = 9;
/**
* The application exceeded the maximum cold start time - the app has not been
* launched since last system start, died or was killed.
* The application exceeded the maximum cold start time - the app has not been launched
* since last system start, died or was killed.
*/
int SLOW_COLD_START_TIME = 10;
/**
* The application exceeded the maximum hot start time - the app and activity are
* already in memory.
* The application exceeded the maximum hot start time - the app and activity are already in
* memory.
*/
int SLOW_HOT_START_TIME = 11;
/**
* The application exceeded the maximum warm start time - the app was already in
* memory but the activity wasnt created yet or was removed from memory.
* The application exceeded the maximum warm start time - the app was already in memory but
* the activity wasnt created yet or was removed from memory.
*/
int SLOW_WARM_START_TIME = 12;
/**
* The application exceeded the maximum number of syncs while in the background.
*/
/** The application exceeded the maximum number of syncs while in the background. */
int EXCESSIVE_BACKGROUND_SYNCS = 13;
/**
* The application exceeded the maximum number of gps scans while in the background.
*/
/** The application exceeded the maximum number of gps scans while in the background. */
int EXCESSIVE_GPS_SCANS_IN_BACKGROUND = 14;
/**
* The application scheduled more than the maximum number of jobs while not charging.
*/
/** The application scheduled more than the maximum number of jobs while not charging. */
int EXCESSIVE_JOB_SCHEDULING = 15;
/**
* The application exceeded the maximum amount of mobile network traffic while in
* the background.
* The application exceeded the maximum amount of mobile network traffic while in the
* background.
*/
int EXCESSIVE_MOBILE_NETWORK_IN_BACKGROUND = 16;
/**
* The application held the WiFi lock for more than the maximum amount of time while
* not charging.
* The application held the WiFi lock for more than the maximum amount of time while not
* charging.
*/
int EXCESSIVE_WIFI_LOCK_TIME = 17;
/**
* The application scheduled a job that ran longer than the maximum amount of time.
*/
/** The application scheduled a job that ran longer than the maximum amount of time. */
int JOB_TIMED_OUT = 18;
/**
* The application did an unoptimized Bluetooth scan that exceeded the maximum
* time while in the background.
* The application did an unoptimized Bluetooth scan that exceeded the maximum time while in
* the background.
*/
int LONG_UNOPTIMIZED_BLE_SCAN = 19;
/**
* The application exceeded the maximum ANR rate while in the background.
*/
/** The application exceeded the maximum ANR rate while in the background. */
int BACKGROUND_ANR = 20;
/**
* The application exceeded the maximum crash rate while in the background.
*/
/** The application exceeded the maximum crash rate while in the background. */
int BACKGROUND_CRASH_RATE = 21;
/**
* The application exceeded the maximum ANR-looping rate.
*/
/** The application exceeded the maximum ANR-looping rate. */
int EXCESSIVE_ANR_LOOPING = 22;
/**
* The application exceeded the maximum ANR rate.
*/
/** The application exceeded the maximum ANR rate. */
int EXCESSIVE_ANRS = 23;
/**
* The application exceeded the maximum crash rate.
*/
/** The application exceeded the maximum crash rate. */
int EXCESSIVE_CRASH_RATE = 24;
/**
* The application exceeded the maximum crash-looping rate.
*/
/** The application exceeded the maximum crash-looping rate. */
int EXCESSIVE_CRASH_LOOPING = 25;
/**
* The application crashed because no more file descriptors were available.
*/
/** The application crashed because no more file descriptors were available. */
int NUMBER_OF_OPEN_FILES = 26;
/**
* The application used an excessive amount of CPU while in a
* background process state.
*/
/** The application used an excessive amount of CPU while in a background process state. */
int EXCESSIVE_CPU_USAGE_IN_BACKGROUND = 27;
/**
* The application kept the camera open for an excessive amount
* of time while in a bckground process state.
* The application kept the camera open for an excessive amount of time while in a bckground
* process state.
*/
int EXCESSIVE_CAMERA_USAGE_IN_BACKGROUND = 28;
/**
* The application has accessed the contacts content provider an
* excessive amount.
*/
/** The application has accessed the contacts content provider an excessive amount. */
int EXCESSIVE_CONTACT_ACCESS = 29;
/**
* The application has played too much audio while in a background
* process state.
*/
/** The application has played too much audio while in a background process state. */
int EXCESSIVE_AUDIO_IN_BACKGROUND = 30;
/**
* The application has crashed or ANRed too many times while in a
* background process state.
* The application has crashed or ANRed too many times while in a background process state.
*/
int EXCESSIVE_CRASH_ANR_IN_BACKGROUND = 31;
/**
* An application which has not been used by the user recently
* was detected to cause an excessive amount of battery drain.
* An application which has not been used by the user recently was detected to cause an
* excessive amount of battery drain.
*/
int BATTERY_DRAIN_FROM_UNUSED_APP = 32;
}
}

View File

@@ -28,14 +28,12 @@ public class BatterySaverAction extends BatteryTipAction {
super(context);
}
/**
* Handle the action when user clicks positive button
*/
/** Handle the action when user clicks positive button */
@Override
public void handlePositiveAction(int metricsKey) {
BatterySaverUtils.setPowerSaveMode(mContext, true, /*needFirstTimeWarning*/ true,
SAVER_ENABLED_UNKNOWN);
mMetricsFeatureProvider.action(mContext,
SettingsEnums.ACTION_TIP_TURN_ON_BATTERY_SAVER, metricsKey);
BatterySaverUtils.setPowerSaveMode(
mContext, true, /*needFirstTimeWarning*/ true, SAVER_ENABLED_UNKNOWN);
mMetricsFeatureProvider.action(
mContext, SettingsEnums.ACTION_TIP_TURN_ON_BATTERY_SAVER, metricsKey);
}
}

View File

@@ -33,8 +33,6 @@ public abstract class BatteryTipAction {
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
}
/**
* Handle the action when user clicks positive button
*/
/** Handle the action when user clicks positive button */
public abstract void handlePositiveAction(int metricsKey);
}

View File

@@ -22,23 +22,18 @@ import android.content.Context;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.fuelgauge.batterysaver.BatterySaverSettings;
/**
*
* Action to open the {@link com.android.settings.fuelgauge.batterysaver.BatterySaverSettings}
*/
/** Action to open the {@link com.android.settings.fuelgauge.batterysaver.BatterySaverSettings} */
public class OpenBatterySaverAction extends BatteryTipAction {
public OpenBatterySaverAction(Context context) {
super(context);
}
/**
* Handle the action when user clicks positive button
*/
/** Handle the action when user clicks positive button */
@Override
public void handlePositiveAction(int metricsKey) {
mMetricsFeatureProvider.action(mContext,
SettingsEnums.ACTION_TIP_OPEN_BATTERY_SAVER_PAGE, metricsKey);
mMetricsFeatureProvider.action(
mContext, SettingsEnums.ACTION_TIP_OPEN_BATTERY_SAVER_PAGE, metricsKey);
new SubSettingLauncher(mContext)
.setDestination(BatterySaverSettings.class.getName())
.setSourceMetricsCategory(metricsKey)

View File

@@ -30,35 +30,32 @@ import com.android.settingslib.utils.ThreadUtils;
import java.util.List;
/**
* Action to open the {@link com.android.settings.fuelgauge.RestrictedAppDetails}
*/
/** Action to open the {@link com.android.settings.fuelgauge.RestrictedAppDetails} */
public class OpenRestrictAppFragmentAction extends BatteryTipAction {
private final RestrictAppTip mRestrictAppTip;
private final InstrumentedPreferenceFragment mFragment;
@VisibleForTesting
BatteryDatabaseManager mBatteryDatabaseManager;
@VisibleForTesting BatteryDatabaseManager mBatteryDatabaseManager;
public OpenRestrictAppFragmentAction(InstrumentedPreferenceFragment fragment,
RestrictAppTip tip) {
public OpenRestrictAppFragmentAction(
InstrumentedPreferenceFragment fragment, RestrictAppTip tip) {
super(fragment.getContext());
mFragment = fragment;
mRestrictAppTip = tip;
mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(mContext);
}
/**
* Handle the action when user clicks positive button
*/
/** Handle the action when user clicks positive button */
@Override
public void handlePositiveAction(int metricsKey) {
mMetricsFeatureProvider.action(mContext,
SettingsEnums.ACTION_TIP_OPEN_APP_RESTRICTION_PAGE, metricsKey);
mMetricsFeatureProvider.action(
mContext, SettingsEnums.ACTION_TIP_OPEN_APP_RESTRICTION_PAGE, metricsKey);
final List<AppInfo> mAppInfos = mRestrictAppTip.getRestrictAppList();
RestrictedAppDetails.startRestrictedAppDetails(mFragment, mAppInfos);
// Mark all the anomalies as handled, so it won't show up again.
ThreadUtils.postOnBackgroundThread(() -> mBatteryDatabaseManager.updateAnomalies(mAppInfos,
AnomalyDatabaseHelper.State.HANDLED));
ThreadUtils.postOnBackgroundThread(
() ->
mBatteryDatabaseManager.updateAnomalies(
mAppInfos, AnomalyDatabaseHelper.State.HANDLED));
}
}

View File

@@ -31,15 +31,11 @@ import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
import java.util.List;
/**
* Action to restrict the apps, then app is not allowed to run in the background.
*/
/** Action to restrict the apps, then app is not allowed to run in the background. */
public class RestrictAppAction extends BatteryTipAction {
private RestrictAppTip mRestrictAppTip;
@VisibleForTesting
BatteryDatabaseManager mBatteryDatabaseManager;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@VisibleForTesting BatteryDatabaseManager mBatteryDatabaseManager;
@VisibleForTesting BatteryUtils mBatteryUtils;
public RestrictAppAction(Context context, RestrictAppTip tip) {
super(context);
@@ -48,9 +44,7 @@ public class RestrictAppAction extends BatteryTipAction {
mBatteryDatabaseManager = BatteryDatabaseManager.getInstance(context);
}
/**
* Handle the action when user clicks positive button
*/
/** Handle the action when user clicks positive button */
@Override
public void handlePositiveAction(int metricsKey) {
final List<AppInfo> appInfos = mRestrictAppTip.getRestrictAppList();
@@ -59,18 +53,19 @@ public class RestrictAppAction extends BatteryTipAction {
final AppInfo appInfo = appInfos.get(i);
final String packageName = appInfo.packageName;
// Force app standby, then app can't run in the background
mBatteryUtils.setForceAppStandby(appInfo.uid, packageName,
AppOpsManager.MODE_IGNORED);
mBatteryUtils.setForceAppStandby(appInfo.uid, packageName, AppOpsManager.MODE_IGNORED);
if (CollectionUtils.isEmpty(appInfo.anomalyTypes)) {
// Only log context if there is no anomaly type
mMetricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN,
mMetricsFeatureProvider.action(
SettingsEnums.PAGE_UNKNOWN,
SettingsEnums.ACTION_TIP_RESTRICT_APP,
metricsKey,
packageName,
0);
} else {
for (int type : appInfo.anomalyTypes) {
mMetricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN,
mMetricsFeatureProvider.action(
SettingsEnums.PAGE_UNKNOWN,
SettingsEnums.ACTION_TIP_RESTRICT_APP,
metricsKey,
packageName,

View File

@@ -36,20 +36,18 @@ public class SmartBatteryAction extends BatteryTipAction {
mFragment = fragment;
}
/**
* Handle the action when user clicks positive button
*/
/** Handle the action when user clicks positive button */
@Override
public void handlePositiveAction(int metricsKey) {
mMetricsFeatureProvider.action(mContext,
SettingsEnums.ACTION_TIP_OPEN_SMART_BATTERY, metricsKey);
mMetricsFeatureProvider.action(
mContext, SettingsEnums.ACTION_TIP_OPEN_SMART_BATTERY, metricsKey);
new SubSettingLauncher(mSettingsActivity)
.setSourceMetricsCategory(mFragment instanceof Instrumentable
? ((Instrumentable) mFragment).getMetricsCategory()
: Instrumentable.METRICS_CATEGORY_UNKNOWN)
.setSourceMetricsCategory(
mFragment instanceof Instrumentable
? ((Instrumentable) mFragment).getMetricsCategory()
: Instrumentable.METRICS_CATEGORY_UNKNOWN)
.setDestination(SmartBatterySettings.class.getName())
.setTitleRes(R.string.smart_battery_manager_title)
.launch();
}
}

View File

@@ -26,13 +26,10 @@ import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.AppInfo;
import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip;
/**
* Action to clear the restriction to the app
*/
/** Action to clear the restriction to the app */
public class UnrestrictAppAction extends BatteryTipAction {
private UnrestrictAppTip mUnRestrictAppTip;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@VisibleForTesting BatteryUtils mBatteryUtils;
public UnrestrictAppAction(Context context, UnrestrictAppTip tip) {
super(context);
@@ -40,15 +37,13 @@ public class UnrestrictAppAction extends BatteryTipAction {
mBatteryUtils = BatteryUtils.getInstance(context);
}
/**
* Handle the action when user clicks positive button
*/
/** Handle the action when user clicks positive button */
@Override
public void handlePositiveAction(int metricsKey) {
final AppInfo appInfo = mUnRestrictAppTip.getUnrestrictAppInfo();
// Clear force app standby, then app can run in the background
mBatteryUtils.setForceAppStandby(appInfo.uid, appInfo.packageName,
AppOpsManager.MODE_ALLOWED);
mBatteryUtils.setForceAppStandby(
appInfo.uid, appInfo.packageName, AppOpsManager.MODE_ALLOWED);
mMetricsFeatureProvider.action(
SettingsEnums.PAGE_UNKNOWN,
SettingsEnums.ACTION_TIP_UNRESTRICT_APP,

View File

@@ -23,9 +23,7 @@ import com.android.settings.fuelgauge.batterytip.tips.BatteryDefenderTip;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.overlay.FeatureFactory;
/**
* Detect whether the battery is overheated
*/
/** Detect whether the battery is overheated */
public class BatteryDefenderDetector implements BatteryTipDetector {
private final BatteryInfo mBatteryInfo;
private final Context mContext;
@@ -37,11 +35,13 @@ public class BatteryDefenderDetector implements BatteryTipDetector {
@Override
public BatteryTip detect() {
final boolean isBasicBatteryDefend = mBatteryInfo.isBatteryDefender
&& !FeatureFactory.getFeatureFactory().getPowerUsageFeatureProvider()
.isExtraDefend();
final int state = isBasicBatteryDefend
? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE;
final boolean isBasicBatteryDefend =
mBatteryInfo.isBatteryDefender
&& !FeatureFactory.getFeatureFactory()
.getPowerUsageFeatureProvider()
.isExtraDefend();
final int state =
isBasicBatteryDefend ? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE;
final boolean isPluggedIn = mBatteryInfo.pluggedStatus != 0;
return new BatteryDefenderTip(state, isPluggedIn);
}

View File

@@ -23,9 +23,7 @@ import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.DockDefenderTip;
/**
* Detect whether the dock defender mode is enabled.
*/
/** Detect whether the dock defender mode is enabled. */
public class DockDefenderDetector implements BatteryTipDetector {
private final BatteryInfo mBatteryInfo;
private final Context mContext;
@@ -44,5 +42,4 @@ public class DockDefenderDetector implements BatteryTipDetector {
: BatteryTip.StateType.INVISIBLE,
mode);
}
}

View File

@@ -38,8 +38,8 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Detector whether to show summary tip. This detector should be executed as the last
* {@link BatteryTipDetector} since it need the most up-to-date {@code visibleTips}
* Detector whether to show summary tip. This detector should be executed as the last {@link
* BatteryTipDetector} since it need the most up-to-date {@code visibleTips}
*/
public class HighUsageDetector implements BatteryTipDetector {
private static final String TAG = "HighUsageDetector";
@@ -48,29 +48,31 @@ public class HighUsageDetector implements BatteryTipDetector {
private BatteryUsageStats mBatteryUsageStats;
private final BatteryInfo mBatteryInfo;
private List<AppInfo> mHighUsageAppList;
@VisibleForTesting
HighUsageDataParser mDataParser;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@VisibleForTesting
boolean mDischarging;
@VisibleForTesting HighUsageDataParser mDataParser;
@VisibleForTesting BatteryUtils mBatteryUtils;
@VisibleForTesting boolean mDischarging;
public HighUsageDetector(Context context, BatteryTipPolicy policy,
BatteryUsageStats batteryUsageStats, BatteryInfo batteryInfo) {
public HighUsageDetector(
Context context,
BatteryTipPolicy policy,
BatteryUsageStats batteryUsageStats,
BatteryInfo batteryInfo) {
mPolicy = policy;
mBatteryUsageStats = batteryUsageStats;
mBatteryInfo = batteryInfo;
mHighUsageAppList = new ArrayList<>();
mBatteryUtils = BatteryUtils.getInstance(context);
mDataParser = new HighUsageDataParser(mPolicy.highUsagePeriodMs,
mPolicy.highUsageBatteryDraining);
mDataParser =
new HighUsageDataParser(
mPolicy.highUsagePeriodMs, mPolicy.highUsageBatteryDraining);
mDischarging = batteryInfo.discharging;
}
@Override
public BatteryTip detect() {
final long lastFullChargeTimeMs = mBatteryUtils.calculateLastFullChargeTime(
mBatteryUsageStats, System.currentTimeMillis());
final long lastFullChargeTimeMs =
mBatteryUtils.calculateLastFullChargeTime(
mBatteryUsageStats, System.currentTimeMillis());
if (mPolicy.highUsageEnabled && mDischarging) {
parseBatteryData();
if (mDataParser.isDeviceHeavilyUsed() || mPolicy.testHighUsageTip) {
@@ -80,22 +82,25 @@ public class HighUsageDetector implements BatteryTipDetector {
mBatteryUsageStats.getUidBatteryConsumers();
// Sort by descending power
uidBatteryConsumers.sort(
(consumer1, consumer2) -> Double.compare(consumer2.getConsumedPower(),
consumer1.getConsumedPower()));
(consumer1, consumer2) ->
Double.compare(
consumer2.getConsumedPower(),
consumer1.getConsumedPower()));
for (UidBatteryConsumer consumer : uidBatteryConsumers) {
final double percent = mBatteryUtils.calculateBatteryPercent(
consumer.getConsumedPower(), totalPower, dischargeAmount);
final double percent =
mBatteryUtils.calculateBatteryPercent(
consumer.getConsumedPower(), totalPower, dischargeAmount);
if ((percent + 0.5f < 1f)
|| mBatteryUtils.shouldHideUidBatteryConsumer(consumer)) {
// Don't show it if we should hide or usage percentage is lower than 1%
continue;
}
mHighUsageAppList.add(new AppInfo.Builder()
.setUid(consumer.getUid())
.setPackageName(
mBatteryUtils.getPackageName(consumer.getUid()))
.build());
mHighUsageAppList.add(
new AppInfo.Builder()
.setUid(consumer.getUid())
.setPackageName(mBatteryUtils.getPackageName(consumer.getUid()))
.build());
if (mHighUsageAppList.size() >= mPolicy.highUsageAppCount) {
break;
}
@@ -103,10 +108,11 @@ public class HighUsageDetector implements BatteryTipDetector {
// When in test mode, add an app if necessary
if (mPolicy.testHighUsageTip && mHighUsageAppList.isEmpty()) {
mHighUsageAppList.add(new AppInfo.Builder()
.setPackageName(SETTINGS_PACKAGE_NAME)
.setScreenOnTimeMs(TimeUnit.HOURS.toMillis(3))
.build());
mHighUsageAppList.add(
new AppInfo.Builder()
.setPackageName(SETTINGS_PACKAGE_NAME)
.setScreenOnTimeMs(TimeUnit.HOURS.toMillis(3))
.build());
}
}
}

View File

@@ -34,12 +34,12 @@ public final class IncompatibleChargerDetector implements BatteryTipDetector {
@Override
public BatteryTip detect() {
final boolean isIncompatibleCharging =
Utils.containsIncompatibleChargers(mContext, TAG);
final int state = isIncompatibleCharging
? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE;
Log.d(TAG, "detect() state= " + state + " isIncompatibleCharging: "
+ isIncompatibleCharging);
final boolean isIncompatibleCharging = Utils.containsIncompatibleChargers(mContext, TAG);
final int state =
isIncompatibleCharging ? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE;
Log.d(
TAG,
"detect() state= " + state + " isIncompatibleCharging: " + isIncompatibleCharging);
return new IncompatibleChargerTip(state);
}
}

View File

@@ -23,22 +23,23 @@ import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.LowBatteryTip;
/**
* Detect whether the battery is too low
*/
/** Detect whether the battery is too low */
public class LowBatteryDetector implements BatteryTipDetector {
private final BatteryInfo mBatteryInfo;
private final BatteryTipPolicy mPolicy;
private final boolean mIsPowerSaveMode;
private final int mWarningLevel;
public LowBatteryDetector(Context context, BatteryTipPolicy policy, BatteryInfo batteryInfo,
public LowBatteryDetector(
Context context,
BatteryTipPolicy policy,
BatteryInfo batteryInfo,
boolean isPowerSaveMode) {
mPolicy = policy;
mBatteryInfo = batteryInfo;
mWarningLevel = context.getResources().getInteger(
com.android.internal.R.integer.config_lowBatteryWarningLevel);
mWarningLevel =
context.getResources()
.getInteger(com.android.internal.R.integer.config_lowBatteryWarningLevel);
mIsPowerSaveMode = isPowerSaveMode;
}

View File

@@ -25,9 +25,7 @@ import com.android.settings.fuelgauge.batterytip.BatteryTipPolicy;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.SmartBatteryTip;
/**
* Detect whether to show smart battery tip.
*/
/** Detect whether to show smart battery tip. */
public class SmartBatteryDetector implements BatteryTipDetector {
private static final int EXPECTED_BATTERY_LEVEL = 30;
@@ -36,8 +34,12 @@ public class SmartBatteryDetector implements BatteryTipDetector {
private final ContentResolver mContentResolver;
private final boolean mIsPowerSaveMode;
public SmartBatteryDetector(Context context, BatteryTipPolicy policy, BatteryInfo batteryInfo,
ContentResolver contentResolver, boolean isPowerSaveMode) {
public SmartBatteryDetector(
Context context,
BatteryTipPolicy policy,
BatteryInfo batteryInfo,
ContentResolver contentResolver,
boolean isPowerSaveMode) {
mPolicy = policy;
mBatteryInfo = batteryInfo;
mContentResolver = contentResolver;
@@ -46,14 +48,18 @@ public class SmartBatteryDetector implements BatteryTipDetector {
@Override
public BatteryTip detect() {
final boolean smartBatteryOff = Settings.Global.getInt(mContentResolver,
Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, 1) == 0;
final boolean smartBatteryOff =
Settings.Global.getInt(
mContentResolver,
Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED,
1)
== 0;
final boolean isUnderExpectedBatteryLevel =
mBatteryInfo.batteryLevel <= EXPECTED_BATTERY_LEVEL;
// Show it if in test or smart battery is off.
final boolean enableSmartBatteryTip =
smartBatteryOff && !mIsPowerSaveMode && isUnderExpectedBatteryLevel
|| mPolicy.testSmartBatteryTip;
|| mPolicy.testSmartBatteryTip;
final int state =
enableSmartBatteryTip ? BatteryTip.StateType.NEW : BatteryTip.StateType.INVISIBLE;
return new SmartBatteryTip(state);

View File

@@ -23,9 +23,7 @@ import com.android.settings.fuelgauge.batterytip.AppInfo;
import java.util.function.Predicate;
/**
* {@link Predicate} for {@link AppInfo} to check whether it has label
*/
/** {@link Predicate} for {@link AppInfo} to check whether it has label */
public class AppLabelPredicate implements Predicate<AppInfo> {
private static AppLabelPredicate sInstance;

View File

@@ -23,9 +23,7 @@ import com.android.settings.fuelgauge.batterytip.AppInfo;
import java.util.function.Predicate;
/**
* {@link Predicate} for {@link AppInfo} to check whether it is restricted.
*/
/** {@link Predicate} for {@link AppInfo} to check whether it is restricted. */
public class AppRestrictionPredicate implements Predicate<AppInfo> {
private static AppRestrictionPredicate sInstance;
@@ -46,7 +44,8 @@ public class AppRestrictionPredicate implements Predicate<AppInfo> {
@Override
public boolean test(AppInfo appInfo) {
// Return true if app already been restricted
return mAppOpsManager.checkOpNoThrow(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
appInfo.uid, appInfo.packageName) == AppOpsManager.MODE_IGNORED;
return mAppOpsManager.checkOpNoThrow(
AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, appInfo.uid, appInfo.packageName)
== AppOpsManager.MODE_IGNORED;
}
}

View File

@@ -30,9 +30,7 @@ import com.android.settings.widget.CardPreference;
import com.android.settingslib.HelpUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/**
* Tip to show current battery is overheated
*/
/** Tip to show current battery is overheated */
public class BatteryDefenderTip extends BatteryTip {
private static final String TAG = "BatteryDefenderTip";
@@ -70,8 +68,7 @@ public class BatteryDefenderTip extends BatteryTip {
@Override
public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) {
metricsFeatureProvider.action(context, SettingsEnums.ACTION_BATTERY_DEFENDER_TIP,
mState);
metricsFeatureProvider.action(context, SettingsEnums.ACTION_BATTERY_DEFENDER_TIP, mState);
}
@Override
@@ -97,14 +94,17 @@ public class BatteryDefenderTip extends BatteryTip {
cardPreference.setSecondaryButtonText(context.getString(R.string.learn_more));
cardPreference.setSecondaryButtonClickListener(
button -> button.startActivityForResult(
HelpUtils.getHelpIntent(
context,
context.getString(R.string.help_url_battery_defender),
/* backupContext */ ""), /* requestCode */ 0));
button ->
button.startActivityForResult(
HelpUtils.getHelpIntent(
context,
context.getString(R.string.help_url_battery_defender),
/* backupContext */ ""), /* requestCode */
0));
cardPreference.setSecondaryButtonVisible(true);
cardPreference.setSecondaryButtonContentDescription(context.getString(
R.string.battery_tip_limited_temporarily_sec_button_content_description));
cardPreference.setSecondaryButtonContentDescription(
context.getString(
R.string.battery_tip_limited_temporarily_sec_button_content_description));
}
private void resumeCharging(Context context) {
@@ -119,13 +119,14 @@ public class BatteryDefenderTip extends BatteryTip {
Log.i(TAG, "send resume charging broadcast intent=" + intent);
}
public static final Creator CREATOR = new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new BatteryDefenderTip(in);
}
public static final Creator CREATOR =
new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new BatteryDefenderTip(in);
}
public BatteryTip[] newArray(int size) {
return new BatteryDefenderTip[size];
}
};
public BatteryTip[] newArray(int size) {
return new BatteryDefenderTip[size];
}
};
}

View File

@@ -35,14 +35,12 @@ import java.lang.annotation.RetentionPolicy;
/**
* Base model for a battery tip(e.g. suggest user to turn on battery saver)
*
* Each {@link BatteryTip} contains basic data(e.g. title, summary, icon) as well as the
* <p>Each {@link BatteryTip} contains basic data(e.g. title, summary, icon) as well as the
* pre-defined action(e.g. turn on battery saver)
*/
public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
@Retention(RetentionPolicy.SOURCE)
@IntDef({StateType.NEW,
StateType.HANDLED,
StateType.INVISIBLE})
@IntDef({StateType.NEW, StateType.HANDLED, StateType.INVISIBLE})
public @interface StateType {
int NEW = 0;
int HANDLED = 1;
@@ -50,17 +48,19 @@ public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
}
@Retention(RetentionPolicy.SOURCE)
@IntDef({TipType.SUMMARY,
TipType.BATTERY_SAVER,
TipType.HIGH_DEVICE_USAGE,
TipType.SMART_BATTERY_MANAGER,
TipType.APP_RESTRICTION,
TipType.REDUCED_BATTERY,
TipType.LOW_BATTERY,
TipType.REMOVE_APP_RESTRICTION,
TipType.BATTERY_DEFENDER,
TipType.DOCK_DEFENDER,
TipType.INCOMPATIBLE_CHARGER})
@IntDef({
TipType.SUMMARY,
TipType.BATTERY_SAVER,
TipType.HIGH_DEVICE_USAGE,
TipType.SMART_BATTERY_MANAGER,
TipType.APP_RESTRICTION,
TipType.REDUCED_BATTERY,
TipType.LOW_BATTERY,
TipType.REMOVE_APP_RESTRICTION,
TipType.BATTERY_DEFENDER,
TipType.DOCK_DEFENDER,
TipType.INCOMPATIBLE_CHARGER
})
public @interface TipType {
int SMART_BATTERY_MANAGER = 0;
int APP_RESTRICTION = 1;
@@ -75,8 +75,8 @@ public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
int INCOMPATIBLE_CHARGER = 10;
}
@VisibleForTesting
static final SparseIntArray TIP_ORDER;
@VisibleForTesting static final SparseIntArray TIP_ORDER;
static {
TIP_ORDER = new SparseIntArray();
TIP_ORDER.append(TipType.BATTERY_SAVER, 0);
@@ -97,9 +97,8 @@ public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
protected int mType;
protected int mState;
protected boolean mShowDialog;
/**
* Whether we need to update battery tip when configuration change
*/
/** Whether we need to update battery tip when configuration change */
protected boolean mNeedUpdate;
BatteryTip(Parcel in) {
@@ -146,15 +145,14 @@ public abstract class BatteryTip implements Comparable<BatteryTip>, Parcelable {
/**
* Check whether data is still make sense. If not, try recover.
*
* @param context used to do validate check
*/
public void validateCheck(Context context) {
// do nothing
}
/**
* Log the battery tip
*/
/** Log the battery tip */
public abstract void log(Context context, MetricsFeatureProvider metricsFeatureProvider);
public void updatePreference(Preference preference) {

View File

@@ -32,9 +32,7 @@ import com.android.settings.widget.CardPreference;
import com.android.settingslib.HelpUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/**
* Tip to show dock defender status
*/
/** Tip to show dock defender status */
public class DockDefenderTip extends BatteryTip {
private static final String TAG = "DockDefenderTip";
private int mMode;
@@ -84,8 +82,9 @@ public class DockDefenderTip extends BatteryTip {
@Override
public int getIconId() {
return mMode == DockDefenderMode.ACTIVE ? R.drawable.ic_battery_status_protected_24dp :
R.drawable.ic_battery_dock_defender_untriggered_24dp;
return mMode == DockDefenderMode.ACTIVE
? R.drawable.ic_battery_status_protected_24dp
: R.drawable.ic_battery_dock_defender_untriggered_24dp;
}
@Override
@@ -98,8 +97,7 @@ public class DockDefenderTip extends BatteryTip {
@Override
public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) {
metricsFeatureProvider.action(context, SettingsEnums.ACTION_DOCK_DEFENDER_TIP,
mState);
metricsFeatureProvider.action(context, SettingsEnums.ACTION_DOCK_DEFENDER_TIP, mState);
}
@Override
@@ -119,15 +117,19 @@ public class DockDefenderTip extends BatteryTip {
case DockDefenderMode.ACTIVE:
cardPreference.setPrimaryButtonText(
context.getString(R.string.battery_tip_charge_to_full_button));
cardPreference.setPrimaryButtonClickListener(unused -> {
resumeCharging(context);
mMode = DockDefenderMode.TEMPORARILY_BYPASSED;
context.sendBroadcast(new Intent().setAction(
BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION).setPackage(
context.getPackageName()).addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND));
updatePreference(preference);
});
cardPreference.setPrimaryButtonClickListener(
unused -> {
resumeCharging(context);
mMode = DockDefenderMode.TEMPORARILY_BYPASSED;
context.sendBroadcast(
new Intent()
.setAction(BatteryUtils.BYPASS_DOCK_DEFENDER_ACTION)
.setPackage(context.getPackageName())
.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND));
updatePreference(preference);
});
cardPreference.setPrimaryButtonVisible(true);
break;
case DockDefenderMode.TEMPORARILY_BYPASSED:
@@ -140,15 +142,17 @@ public class DockDefenderTip extends BatteryTip {
cardPreference.setSecondaryButtonText(context.getString(R.string.learn_more));
cardPreference.setSecondaryButtonClickListener(
button -> button.startActivityForResult(
HelpUtils.getHelpIntent(
context,
context.getString(R.string.help_url_dock_defender),
/* backupContext */ ""), /* requestCode */ 0));
button ->
button.startActivityForResult(
HelpUtils.getHelpIntent(
context,
context.getString(R.string.help_url_dock_defender),
/* backupContext */ ""), /* requestCode */
0));
cardPreference.setSecondaryButtonVisible(true);
cardPreference.setSecondaryButtonContentDescription(context.getString(
R.string.battery_tip_limited_temporarily_sec_button_content_description));
cardPreference.setSecondaryButtonContentDescription(
context.getString(
R.string.battery_tip_limited_temporarily_sec_button_content_description));
}
private void resumeCharging(Context context) {
@@ -163,13 +167,14 @@ public class DockDefenderTip extends BatteryTip {
Log.i(TAG, "send resume charging broadcast intent=" + intent);
}
public static final Creator CREATOR = new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new DockDefenderTip(in);
}
public static final Creator CREATOR =
new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new DockDefenderTip(in);
}
public BatteryTip[] newArray(int size) {
return new DockDefenderTip[size];
}
};
public BatteryTip[] newArray(int size) {
return new DockDefenderTip[size];
}
};
}

View File

@@ -29,17 +29,16 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import java.util.List;
/**
* Tip to show general summary about battery life
*/
/** Tip to show general summary about battery life */
public class HighUsageTip extends BatteryTip {
private final long mLastFullChargeTimeMs;
@VisibleForTesting
final List<AppInfo> mHighUsageAppList;
@VisibleForTesting final List<AppInfo> mHighUsageAppList;
public HighUsageTip(long lastFullChargeTimeMs, List<AppInfo> appList) {
super(TipType.HIGH_DEVICE_USAGE, appList.isEmpty() ? StateType.INVISIBLE : StateType.NEW,
super(
TipType.HIGH_DEVICE_USAGE,
appList.isEmpty() ? StateType.INVISIBLE : StateType.NEW,
true /* showDialog */);
mLastFullChargeTimeMs = lastFullChargeTimeMs;
mHighUsageAppList = appList;
@@ -81,13 +80,11 @@ public class HighUsageTip extends BatteryTip {
@Override
public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) {
metricsFeatureProvider.action(context, SettingsEnums.ACTION_HIGH_USAGE_TIP,
mState);
metricsFeatureProvider.action(context, SettingsEnums.ACTION_HIGH_USAGE_TIP, mState);
for (int i = 0, size = mHighUsageAppList.size(); i < size; i++) {
final AppInfo appInfo = mHighUsageAppList.get(i);
metricsFeatureProvider.action(context,
SettingsEnums.ACTION_HIGH_USAGE_TIP_LIST,
appInfo.packageName);
metricsFeatureProvider.action(
context, SettingsEnums.ACTION_HIGH_USAGE_TIP_LIST, appInfo.packageName);
}
}
@@ -112,14 +109,14 @@ public class HighUsageTip extends BatteryTip {
return stringBuilder.toString();
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new HighUsageTip(in);
}
public BatteryTip[] newArray(int size) {
return new HighUsageTip[size];
}
};
public static final Parcelable.Creator CREATOR =
new Parcelable.Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new HighUsageTip(in);
}
public BatteryTip[] newArray(int size) {
return new HighUsageTip[size];
}
};
}

View File

@@ -62,8 +62,8 @@ public final class IncompatibleChargerTip extends BatteryTip {
@Override
public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) {
metricsFeatureProvider.action(context, SettingsEnums.ACTION_INCOMPATIBLE_CHARGING_TIP,
mState);
metricsFeatureProvider.action(
context, SettingsEnums.ACTION_INCOMPATIBLE_CHARGING_TIP, mState);
}
@Override
@@ -79,23 +79,26 @@ public final class IncompatibleChargerTip extends BatteryTip {
cardPreference.setSelectable(false);
cardPreference.setPrimaryButtonText(context.getString(R.string.learn_more));
cardPreference.setPrimaryButtonClickListener(
button -> button.startActivityForResult(
HelpUtils.getHelpIntent(
context,
context.getString(R.string.help_url_incompatible_charging),
/* backupContext */ ""), /* requestCode */ 0));
button ->
button.startActivityForResult(
HelpUtils.getHelpIntent(
context,
context.getString(R.string.help_url_incompatible_charging),
/* backupContext */ ""), /* requestCode */
0));
cardPreference.setPrimaryButtonVisible(true);
cardPreference.setPrimaryButtonContentDescription(context.getString(
R.string.battery_tip_incompatible_charging_content_description));
cardPreference.setPrimaryButtonContentDescription(
context.getString(R.string.battery_tip_incompatible_charging_content_description));
}
public static final Creator CREATOR = new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new IncompatibleChargerTip(in);
}
public static final Creator CREATOR =
new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new IncompatibleChargerTip(in);
}
public BatteryTip[] newArray(int size) {
return new IncompatibleChargerTip[size];
}
};
public BatteryTip[] newArray(int size) {
return new IncompatibleChargerTip[size];
}
};
}

View File

@@ -62,28 +62,27 @@ public class LowBatteryTip extends BatteryTip {
@Override
public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) {
metricsFeatureProvider.action(context, SettingsEnums.ACTION_LOW_BATTERY_TIP,
mState);
metricsFeatureProvider.action(context, SettingsEnums.ACTION_LOW_BATTERY_TIP, mState);
}
@Override
public void updateState(BatteryTip tip) {
final LowBatteryTip lowBatteryTip = (LowBatteryTip) tip;
mState = lowBatteryTip.mPowerSaveModeOn
? StateType.INVISIBLE : lowBatteryTip.getState();
mState = lowBatteryTip.mPowerSaveModeOn ? StateType.INVISIBLE : lowBatteryTip.getState();
}
boolean isPowerSaveModeOn() {
return mPowerSaveModeOn;
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new LowBatteryTip(in);
}
public static final Parcelable.Creator CREATOR =
new Parcelable.Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new LowBatteryTip(in);
}
public BatteryTip[] newArray(int size) {
return new LowBatteryTip[size];
}
};
public BatteryTip[] newArray(int size) {
return new LowBatteryTip[size];
}
};
}

View File

@@ -34,9 +34,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Tip to suggest user to restrict some bad apps
*/
/** Tip to suggest user to restrict some bad apps */
public class RestrictAppTip extends BatteryTip {
private List<AppInfo> mRestrictAppList;
@@ -62,27 +60,32 @@ public class RestrictAppTip extends BatteryTip {
@Override
public CharSequence getTitle(Context context) {
final int num = mRestrictAppList.size();
final CharSequence appLabel = num > 0 ? Utils.getApplicationLabel(context,
mRestrictAppList.get(0).packageName) : "";
final CharSequence appLabel =
num > 0
? Utils.getApplicationLabel(context, mRestrictAppList.get(0).packageName)
: "";
Map<String, Object> arguments = new ArrayMap<>();
arguments.put("count", num);
arguments.put("label", appLabel);
return mState == StateType.HANDLED
? StringUtil.getIcuPluralsString(context, arguments,
R.string.battery_tip_restrict_handled_title)
: StringUtil.getIcuPluralsString(context, arguments,
R.string.battery_tip_restrict_title);
? StringUtil.getIcuPluralsString(
context, arguments, R.string.battery_tip_restrict_handled_title)
: StringUtil.getIcuPluralsString(
context, arguments, R.string.battery_tip_restrict_title);
}
@Override
public CharSequence getSummary(Context context) {
final int num = mRestrictAppList.size();
final CharSequence appLabel = num > 0 ? Utils.getApplicationLabel(context,
mRestrictAppList.get(0).packageName) : "";
final int resId = mState == StateType.HANDLED
? R.string.battery_tip_restrict_handled_summary
: R.string.battery_tip_restrict_summary;
final CharSequence appLabel =
num > 0
? Utils.getApplicationLabel(context, mRestrictAppList.get(0).packageName)
: "";
final int resId =
mState == StateType.HANDLED
? R.string.battery_tip_restrict_handled_summary
: R.string.battery_tip_restrict_summary;
Map<String, Object> arguments = new ArrayMap<>();
arguments.put("count", num);
arguments.put("label", appLabel);
@@ -127,13 +130,13 @@ public class RestrictAppTip extends BatteryTip {
@Override
public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) {
metricsFeatureProvider.action(context, SettingsEnums.ACTION_APP_RESTRICTION_TIP,
mState);
metricsFeatureProvider.action(context, SettingsEnums.ACTION_APP_RESTRICTION_TIP, mState);
if (mState == StateType.NEW) {
for (int i = 0, size = mRestrictAppList.size(); i < size; i++) {
final AppInfo appInfo = mRestrictAppList.get(i);
for (Integer anomalyType : appInfo.anomalyTypes) {
metricsFeatureProvider.action(SettingsEnums.PAGE_UNKNOWN,
metricsFeatureProvider.action(
SettingsEnums.PAGE_UNKNOWN,
SettingsEnums.ACTION_APP_RESTRICTION_TIP_LIST,
SettingsEnums.PAGE_UNKNOWN,
appInfo.packageName,
@@ -147,14 +150,11 @@ public class RestrictAppTip extends BatteryTip {
return mRestrictAppList;
}
/**
* Construct the app list string(e.g. app1, app2, and app3)
*/
/** Construct the app list string(e.g. app1, app2, and app3) */
public CharSequence getRestrictAppsString(Context context) {
final List<CharSequence> appLabels = new ArrayList<>();
for (int i = 0, size = mRestrictAppList.size(); i < size; i++) {
appLabels.add(Utils.getApplicationLabel(context,
mRestrictAppList.get(i).packageName));
appLabels.add(Utils.getApplicationLabel(context, mRestrictAppList.get(i).packageName));
}
return ListFormatter.getInstance().format(appLabels);
@@ -179,13 +179,14 @@ public class RestrictAppTip extends BatteryTip {
dest.writeTypedList(mRestrictAppList);
}
public static final Creator CREATOR = new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new RestrictAppTip(in);
}
public static final Creator CREATOR =
new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new RestrictAppTip(in);
}
public BatteryTip[] newArray(int size) {
return new RestrictAppTip[size];
}
};
public BatteryTip[] newArray(int size) {
return new RestrictAppTip[size];
}
};
}

View File

@@ -23,9 +23,7 @@ import android.os.Parcel;
import com.android.settings.R;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
/**
* Tip to suggest turn on smart battery if it is not on
*/
/** Tip to suggest turn on smart battery if it is not on */
public class SmartBatteryTip extends BatteryTip {
public SmartBatteryTip(@StateType int state) {
@@ -58,18 +56,17 @@ public class SmartBatteryTip extends BatteryTip {
@Override
public void log(Context context, MetricsFeatureProvider metricsFeatureProvider) {
metricsFeatureProvider.action(context, SettingsEnums.ACTION_SMART_BATTERY_TIP,
mState);
metricsFeatureProvider.action(context, SettingsEnums.ACTION_SMART_BATTERY_TIP, mState);
}
public static final Creator CREATOR = new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new SmartBatteryTip(in);
}
public BatteryTip[] newArray(int size) {
return new SmartBatteryTip[size];
}
};
public static final Creator CREATOR =
new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new SmartBatteryTip(in);
}
public BatteryTip[] newArray(int size) {
return new SmartBatteryTip[size];
}
};
}

View File

@@ -84,13 +84,14 @@ public class UnrestrictAppTip extends BatteryTip {
dest.writeParcelable(mAppInfo, flags);
}
public static final Creator CREATOR = new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new UnrestrictAppTip(in);
}
public static final Creator CREATOR =
new Creator() {
public BatteryTip createFromParcel(Parcel in) {
return new UnrestrictAppTip(in);
}
public BatteryTip[] newArray(int size) {
return new UnrestrictAppTip[size];
}
};
public BatteryTip[] newArray(int size) {
return new UnrestrictAppTip[size];
}
};
}

View File

@@ -48,7 +48,8 @@ final class AnomalyEventWrapper {
mResourceIndex = mPowerAnomalyEvent.getKey().getNumber();
}
private <T> T getInfo(Function<WarningBannerInfo, T> warningBannerInfoSupplier,
private <T> T getInfo(
Function<WarningBannerInfo, T> warningBannerInfoSupplier,
Function<WarningItemInfo, T> warningItemInfoSupplier) {
if (warningBannerInfoSupplier != null && mPowerAnomalyEvent.hasWarningBannerInfo()) {
return warningBannerInfoSupplier.apply(mPowerAnomalyEvent.getWarningBannerInfo());
@@ -60,15 +61,19 @@ final class AnomalyEventWrapper {
private int getResourceId(int resourceId, int resourceIndex, String defType) {
final String key = getStringFromArrayResource(resourceId, resourceIndex);
return TextUtils.isEmpty(key) ? 0
return TextUtils.isEmpty(key)
? 0
: mContext.getResources().getIdentifier(key, defType, mContext.getPackageName());
}
private String getString(Function<WarningBannerInfo, String> warningBannerInfoSupplier,
private String getString(
Function<WarningBannerInfo, String> warningBannerInfoSupplier,
Function<WarningItemInfo, String> warningItemInfoSupplier,
int resourceId, int resourceIndex) {
int resourceId,
int resourceIndex) {
final String string = getInfo(warningBannerInfoSupplier, warningItemInfoSupplier);
return (!TextUtils.isEmpty(string) || resourceId <= 0) ? string
return (!TextUtils.isEmpty(string) || resourceId <= 0)
? string
: getStringFromArrayResource(resourceId, resourceIndex);
}
@@ -78,7 +83,8 @@ final class AnomalyEventWrapper {
}
final String[] stringArray = mContext.getResources().getStringArray(resourceId);
return (resourceIndex >= 0 && resourceIndex < stringArray.length)
? stringArray[resourceIndex] : null;
? stringArray[resourceIndex]
: null;
}
void setRelatedBatteryDiffEntry(BatteryDiffEntry batteryDiffEntry) {
@@ -98,13 +104,13 @@ final class AnomalyEventWrapper {
}
String getTitleString() {
final String titleStringFromProto = getInfo(WarningBannerInfo::getTitleString,
WarningItemInfo::getTitleString);
final String titleStringFromProto =
getInfo(WarningBannerInfo::getTitleString, WarningItemInfo::getTitleString);
if (!TextUtils.isEmpty(titleStringFromProto)) {
return titleStringFromProto;
}
final int titleFormatResId = getResourceId(R.array.power_anomaly_title_ids,
mResourceIndex, "string");
final int titleFormatResId =
getResourceId(R.array.power_anomaly_title_ids, mResourceIndex, "string");
if (mPowerAnomalyEvent.hasWarningBannerInfo()) {
return mContext.getString(titleFormatResId);
} else if (mPowerAnomalyEvent.hasWarningItemInfo() && mRelatedBatteryDiffEntry != null) {
@@ -115,20 +121,24 @@ final class AnomalyEventWrapper {
}
String getMainBtnString() {
return getString(WarningBannerInfo::getMainButtonString,
return getString(
WarningBannerInfo::getMainButtonString,
WarningItemInfo::getMainButtonString,
R.array.power_anomaly_main_btn_strings, mResourceIndex);
R.array.power_anomaly_main_btn_strings,
mResourceIndex);
}
String getDismissBtnString() {
return getString(WarningBannerInfo::getCancelButtonString,
return getString(
WarningBannerInfo::getCancelButtonString,
WarningItemInfo::getCancelButtonString,
R.array.power_anomaly_dismiss_btn_strings, mResourceIndex);
R.array.power_anomaly_dismiss_btn_strings,
mResourceIndex);
}
String getAnomalyHintString() {
final String anomalyHintStringFromProto = getInfo(null,
WarningItemInfo::getWarningInfoString);
final String anomalyHintStringFromProto =
getInfo(null, WarningItemInfo::getWarningInfoString);
return TextUtils.isEmpty(anomalyHintStringFromProto)
? getStringFromArrayResource(R.array.power_anomaly_hint_messages, mResourceIndex)
: anomalyHintStringFromProto;
@@ -148,8 +158,9 @@ final class AnomalyEventWrapper {
String getAnomalyEntryKey() {
return mPowerAnomalyEvent.hasWarningItemInfo()
&& mPowerAnomalyEvent.getWarningItemInfo().hasItemKey()
? mPowerAnomalyEvent.getWarningItemInfo().getItemKey() : null;
&& mPowerAnomalyEvent.getWarningItemInfo().hasItemKey()
? mPowerAnomalyEvent.getWarningItemInfo().getItemKey()
: null;
}
boolean hasSubSettingLauncher() {
@@ -163,23 +174,24 @@ final class AnomalyEventWrapper {
if (mSubSettingLauncher != null) {
return mSubSettingLauncher;
}
final String destinationClassName = getInfo(
WarningBannerInfo::getMainButtonDestination, null);
final String destinationClassName =
getInfo(WarningBannerInfo::getMainButtonDestination, null);
if (!TextUtils.isEmpty(destinationClassName)) {
final Integer sourceMetricsCategory = getInfo(
WarningBannerInfo::getMainButtonSourceMetricsCategory, null);
final String preferenceHighlightKey = getInfo(
WarningBannerInfo::getMainButtonSourceHighlightKey, null);
final Integer sourceMetricsCategory =
getInfo(WarningBannerInfo::getMainButtonSourceMetricsCategory, null);
final String preferenceHighlightKey =
getInfo(WarningBannerInfo::getMainButtonSourceHighlightKey, null);
Bundle arguments = Bundle.EMPTY;
if (!TextUtils.isEmpty(preferenceHighlightKey)) {
arguments = new Bundle(1);
arguments.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY,
preferenceHighlightKey);
arguments.putString(
SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, preferenceHighlightKey);
}
mSubSettingLauncher = new SubSettingLauncher(mContext)
.setDestination(destinationClassName)
.setSourceMetricsCategory(sourceMetricsCategory)
.setArguments(arguments);
mSubSettingLauncher =
new SubSettingLauncher(mContext)
.setDestination(destinationClassName)
.setSourceMetricsCategory(sourceMetricsCategory)
.setArguments(arguments);
}
return mSubSettingLauncher;
}
@@ -199,13 +211,13 @@ final class AnomalyEventWrapper {
return null;
}
final WarningItemInfo warningItemInfo = mPowerAnomalyEvent.getWarningItemInfo();
final Long startTimestamp = warningItemInfo.hasStartTimestamp()
? warningItemInfo.getStartTimestamp() : null;
final Long endTimestamp = warningItemInfo.hasEndTimestamp()
? warningItemInfo.getEndTimestamp() : null;
final Long startTimestamp =
warningItemInfo.hasStartTimestamp() ? warningItemInfo.getStartTimestamp() : null;
final Long endTimestamp =
warningItemInfo.hasEndTimestamp() ? warningItemInfo.getEndTimestamp() : null;
if (startTimestamp != null && endTimestamp != null) {
mHighlightSlotPair = batteryLevelData
.getIndexByTimestamps(startTimestamp, endTimestamp);
mHighlightSlotPair =
batteryLevelData.getIndexByTimestamps(startTimestamp, endTimestamp);
if (mHighlightSlotPair.first == BatteryChartViewModel.SELECTED_INDEX_INVALID
|| mHighlightSlotPair.second == BatteryChartViewModel.SELECTED_INDEX_INVALID) {
// Drop invalid mHighlightSlotPair index

View File

@@ -55,8 +55,12 @@ import java.util.Map;
/** Controls the update for chart graph and the list items. */
public class BatteryChartPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin, LifecycleObserver, OnCreate, OnDestroy,
OnSaveInstanceState, OnResume {
implements PreferenceControllerMixin,
LifecycleObserver,
OnCreate,
OnDestroy,
OnSaveInstanceState,
OnResume {
private static final String TAG = "BatteryChartPreferenceController";
private static final String PREFERENCE_KEY = "battery_chart";
@@ -73,22 +77,14 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
void onSelectedIndexUpdated();
}
@VisibleForTesting
Context mPrefContext;
@VisibleForTesting
TextView mChartSummaryTextView;
@VisibleForTesting
BatteryChartView mDailyChartView;
@VisibleForTesting
BatteryChartView mHourlyChartView;
@VisibleForTesting
int mDailyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
@VisibleForTesting
int mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
@VisibleForTesting
int mDailyHighlightSlotIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
@VisibleForTesting
int mHourlyHighlightSlotIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
@VisibleForTesting Context mPrefContext;
@VisibleForTesting TextView mChartSummaryTextView;
@VisibleForTesting BatteryChartView mDailyChartView;
@VisibleForTesting BatteryChartView mHourlyChartView;
@VisibleForTesting int mDailyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
@VisibleForTesting int mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
@VisibleForTesting int mDailyHighlightSlotIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
@VisibleForTesting int mHourlyHighlightSlotIndex = BatteryChartViewModel.SELECTED_INDEX_INVALID;
private boolean mIs24HourFormat;
private View mBatteryChartViewGroup;
@@ -100,13 +96,14 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
private final MetricsFeatureProvider mMetricsFeatureProvider;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final AnimatorListenerAdapter mHourlyChartFadeInAdapter =
createHourlyChartAnimatorListenerAdapter(/*visible=*/ true);
createHourlyChartAnimatorListenerAdapter(/* visible= */ true);
private final AnimatorListenerAdapter mHourlyChartFadeOutAdapter =
createHourlyChartAnimatorListenerAdapter(/*visible=*/ false);
createHourlyChartAnimatorListenerAdapter(/* visible= */ false);
@VisibleForTesting
final DailyChartLabelTextGenerator mDailyChartLabelTextGenerator =
new DailyChartLabelTextGenerator();
@VisibleForTesting
final HourlyChartLabelTextGenerator mHourlyChartLabelTextGenerator =
new HourlyChartLabelTextGenerator();
@@ -116,8 +113,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
super(context);
mActivity = activity;
mIs24HourFormat = DateFormat.is24HourFormat(context);
mMetricsFeatureProvider =
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
if (lifecycle != null) {
lifecycle.addObserver(this);
}
@@ -128,12 +124,13 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
if (savedInstanceState == null) {
return;
}
mDailyChartIndex =
savedInstanceState.getInt(KEY_DAILY_CHART_INDEX, mDailyChartIndex);
mHourlyChartIndex =
savedInstanceState.getInt(KEY_HOURLY_CHART_INDEX, mHourlyChartIndex);
Log.d(TAG, String.format("onCreate() dailyIndex=%d hourlyIndex=%d",
mDailyChartIndex, mHourlyChartIndex));
mDailyChartIndex = savedInstanceState.getInt(KEY_DAILY_CHART_INDEX, mDailyChartIndex);
mHourlyChartIndex = savedInstanceState.getInt(KEY_HOURLY_CHART_INDEX, mHourlyChartIndex);
Log.d(
TAG,
String.format(
"onCreate() dailyIndex=%d hourlyIndex=%d",
mDailyChartIndex, mHourlyChartIndex));
}
@Override
@@ -149,8 +146,11 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
}
savedInstance.putInt(KEY_DAILY_CHART_INDEX, mDailyChartIndex);
savedInstance.putInt(KEY_HOURLY_CHART_INDEX, mHourlyChartIndex);
Log.d(TAG, String.format("onSaveInstanceState() dailyIndex=%d hourlyIndex=%d",
mDailyChartIndex, mHourlyChartIndex));
Log.d(
TAG,
String.format(
"onSaveInstanceState() dailyIndex=%d hourlyIndex=%d",
mDailyChartIndex, mHourlyChartIndex));
}
@Override
@@ -158,7 +158,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
if (mActivity == null || mActivity.isChangingConfigurations()) {
BatteryDiffEntry.clearCache();
}
mHandler.removeCallbacksAndMessages(/*token=*/ null);
mHandler.removeCallbacksAndMessages(/* token= */ null);
}
@Override
@@ -204,19 +204,22 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
refreshUi();
return;
}
mDailyViewModel = new BatteryChartViewModel(
batteryLevelData.getDailyBatteryLevels().getLevels(),
batteryLevelData.getDailyBatteryLevels().getTimestamps(),
BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS,
mDailyChartLabelTextGenerator);
mDailyViewModel =
new BatteryChartViewModel(
batteryLevelData.getDailyBatteryLevels().getLevels(),
batteryLevelData.getDailyBatteryLevels().getTimestamps(),
BatteryChartViewModel.AxisLabelPosition.CENTER_OF_TRAPEZOIDS,
mDailyChartLabelTextGenerator);
mHourlyViewModels = new ArrayList<>();
for (BatteryLevelData.PeriodBatteryLevelData hourlyBatteryLevelsPerDay :
batteryLevelData.getHourlyBatteryLevelsPerDay()) {
mHourlyViewModels.add(new BatteryChartViewModel(
hourlyBatteryLevelsPerDay.getLevels(),
hourlyBatteryLevelsPerDay.getTimestamps(),
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
mHourlyChartLabelTextGenerator.updateSpecialCaseContext(batteryLevelData)));
mHourlyViewModels.add(
new BatteryChartViewModel(
hourlyBatteryLevelsPerDay.getLevels(),
hourlyBatteryLevelsPerDay.getTimestamps(),
BatteryChartViewModel.AxisLabelPosition.BETWEEN_TRAPEZOIDS,
mHourlyChartLabelTextGenerator.updateSpecialCaseContext(
batteryLevelData)));
}
refreshUi();
}
@@ -248,17 +251,21 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
}
mDailyChartIndex = mDailyHighlightSlotIndex;
mHourlyChartIndex = mHourlyHighlightSlotIndex;
Log.d(TAG, String.format("onDailyChartSelect:%d, onHourlyChartSelect:%d",
mDailyChartIndex, mHourlyChartIndex));
Log.d(
TAG,
String.format(
"onDailyChartSelect:%d, onHourlyChartSelect:%d",
mDailyChartIndex, mHourlyChartIndex));
refreshUi();
mHandler.post(() -> mDailyChartView.announceForAccessibility(
getAccessibilityAnnounceMessage()));
mHandler.post(
() -> mDailyChartView.announceForAccessibility(getAccessibilityAnnounceMessage()));
if (mOnSelectedIndexUpdatedListener != null) {
mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
}
}
void setBatteryChartView(@NonNull final BatteryChartView dailyChartView,
void setBatteryChartView(
@NonNull final BatteryChartView dailyChartView,
@NonNull final BatteryChartView hourlyChartView) {
final View parentView = (View) dailyChartView.getParent();
if (parentView != null && parentView.getId() == R.id.battery_chart_group) {
@@ -270,58 +277,67 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
}
if (mBatteryChartViewGroup != null) {
final View grandparentView = (View) mBatteryChartViewGroup.getParent();
mChartSummaryTextView = grandparentView != null
? grandparentView.findViewById(R.id.chart_summary) : null;
mChartSummaryTextView =
grandparentView != null
? grandparentView.findViewById(R.id.chart_summary)
: null;
}
}
private void setBatteryChartViewInner(@NonNull final BatteryChartView dailyChartView,
private void setBatteryChartViewInner(
@NonNull final BatteryChartView dailyChartView,
@NonNull final BatteryChartView hourlyChartView) {
mDailyChartView = dailyChartView;
mDailyChartView.setOnSelectListener(trapezoidIndex -> {
if (mDailyChartIndex == trapezoidIndex) {
return;
}
Log.d(TAG, "onDailyChartSelect:" + trapezoidIndex);
mDailyChartIndex = trapezoidIndex;
mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
refreshUi();
mHandler.post(() -> mDailyChartView.announceForAccessibility(
getAccessibilityAnnounceMessage()));
mMetricsFeatureProvider.action(
mPrefContext,
trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_ALL
? SettingsEnums.ACTION_BATTERY_USAGE_DAILY_SHOW_ALL
: SettingsEnums.ACTION_BATTERY_USAGE_DAILY_TIME_SLOT,
mDailyChartIndex);
if (mOnSelectedIndexUpdatedListener != null) {
mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
}
});
mDailyChartView.setOnSelectListener(
trapezoidIndex -> {
if (mDailyChartIndex == trapezoidIndex) {
return;
}
Log.d(TAG, "onDailyChartSelect:" + trapezoidIndex);
mDailyChartIndex = trapezoidIndex;
mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
refreshUi();
mHandler.post(
() ->
mDailyChartView.announceForAccessibility(
getAccessibilityAnnounceMessage()));
mMetricsFeatureProvider.action(
mPrefContext,
trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_ALL
? SettingsEnums.ACTION_BATTERY_USAGE_DAILY_SHOW_ALL
: SettingsEnums.ACTION_BATTERY_USAGE_DAILY_TIME_SLOT,
mDailyChartIndex);
if (mOnSelectedIndexUpdatedListener != null) {
mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
}
});
mHourlyChartView = hourlyChartView;
mHourlyChartView.setOnSelectListener(trapezoidIndex -> {
if (mDailyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL) {
// This will happen when a daily slot and an hour slot are clicked together.
return;
}
if (mHourlyChartIndex == trapezoidIndex) {
return;
}
Log.d(TAG, "onHourlyChartSelect:" + trapezoidIndex);
mHourlyChartIndex = trapezoidIndex;
refreshUi();
mHandler.post(() -> mHourlyChartView.announceForAccessibility(
getAccessibilityAnnounceMessage()));
mMetricsFeatureProvider.action(
mPrefContext,
trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_ALL
? SettingsEnums.ACTION_BATTERY_USAGE_SHOW_ALL
: SettingsEnums.ACTION_BATTERY_USAGE_TIME_SLOT,
mHourlyChartIndex);
if (mOnSelectedIndexUpdatedListener != null) {
mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
}
});
mHourlyChartView.setOnSelectListener(
trapezoidIndex -> {
if (mDailyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL) {
// This will happen when a daily slot and an hour slot are clicked together.
return;
}
if (mHourlyChartIndex == trapezoidIndex) {
return;
}
Log.d(TAG, "onHourlyChartSelect:" + trapezoidIndex);
mHourlyChartIndex = trapezoidIndex;
refreshUi();
mHandler.post(
() ->
mHourlyChartView.announceForAccessibility(
getAccessibilityAnnounceMessage()));
mMetricsFeatureProvider.action(
mPrefContext,
trapezoidIndex == BatteryChartViewModel.SELECTED_INDEX_ALL
? SettingsEnums.ACTION_BATTERY_USAGE_SHOW_ALL
: SettingsEnums.ACTION_BATTERY_USAGE_TIME_SLOT,
mHourlyChartIndex);
if (mOnSelectedIndexUpdatedListener != null) {
mOnSelectedIndexUpdatedListener.onSelectedIndexUpdated();
}
});
refreshUi();
}
@@ -371,18 +387,18 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
if (mDailyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL) {
// Multiple days are selected, hide the hourly chart view.
animateBatteryHourlyChartView(/*visible=*/ false);
animateBatteryHourlyChartView(/* visible= */ false);
} else {
animateBatteryHourlyChartView(/*visible=*/ true);
final BatteryChartViewModel hourlyViewModel =
mHourlyViewModels.get(mDailyChartIndex);
animateBatteryHourlyChartView(/* visible= */ true);
final BatteryChartViewModel hourlyViewModel = mHourlyViewModels.get(mDailyChartIndex);
if (mHourlyChartIndex >= hourlyViewModel.size()) {
mHourlyChartIndex = BatteryChartViewModel.SELECTED_INDEX_ALL;
}
hourlyViewModel.setSelectedIndex(mHourlyChartIndex);
hourlyViewModel.setHighlightSlotIndex((mDailyChartIndex == mDailyHighlightSlotIndex)
? mHourlyHighlightSlotIndex
: BatteryChartViewModel.SELECTED_INDEX_INVALID);
hourlyViewModel.setHighlightSlotIndex(
(mDailyChartIndex == mDailyHighlightSlotIndex)
? mHourlyHighlightSlotIndex
: BatteryChartViewModel.SELECTED_INDEX_INVALID);
mHourlyChartView.setViewModel(hourlyViewModel);
}
}
@@ -401,8 +417,8 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
return selectedDayText;
}
final String selectedHourText = mHourlyViewModels.get(mDailyChartIndex).getFullText(
mHourlyChartIndex);
final String selectedHourText =
mHourlyViewModels.get(mDailyChartIndex).getFullText(mHourlyChartIndex);
if (isBatteryLevelDataInOneDay()) {
return selectedHourText;
}
@@ -422,7 +438,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
private void animateBatteryChartViewGroup() {
if (mBatteryChartViewGroup != null && mBatteryChartViewGroup.getAlpha() == 0) {
mBatteryChartViewGroup.animate().alpha(1f).setDuration(FADE_IN_ANIMATION_DURATION)
mBatteryChartViewGroup
.animate()
.alpha(1f)
.setDuration(FADE_IN_ANIMATION_DURATION)
.start();
}
}
@@ -435,13 +454,15 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
if (visible) {
mHourlyChartView.setVisibility(View.VISIBLE);
mHourlyChartView.animate()
mHourlyChartView
.animate()
.alpha(1f)
.setDuration(FADE_IN_ANIMATION_DURATION)
.setListener(mHourlyChartFadeInAdapter)
.start();
} else {
mHourlyChartView.animate()
mHourlyChartView
.animate()
.alpha(0f)
.setDuration(FADE_OUT_ANIMATION_DURATION)
.setListener(mHourlyChartFadeOutAdapter)
@@ -467,6 +488,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
mHourlyChartView.setVisibility(visibility);
}
}
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
@@ -483,7 +505,7 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
private boolean isAllSelected() {
return (isBatteryLevelDataInOneDay()
|| mDailyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL)
|| mDailyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL)
&& mHourlyChartIndex == BatteryChartViewModel.SELECTED_INDEX_ALL;
}
@@ -493,8 +515,9 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
return 0;
}
List<Long> dailyTimestamps = batteryLevelData.getDailyBatteryLevels().getTimestamps();
return (int) ((dailyTimestamps.get(dailyTimestamps.size() - 1) - dailyTimestamps.get(0))
/ DateUtils.HOUR_IN_MILLIS);
return (int)
((dailyTimestamps.get(dailyTimestamps.size() - 1) - dailyTimestamps.get(0))
/ DateUtils.HOUR_IN_MILLIS);
}
/** Used for {@link AppBatteryPreferenceController}. */
@@ -505,17 +528,21 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
return null;
}
Log.d(TAG, String.format("getBatterySinceLastFullChargeUsageData() size=%d time=%d/ms",
batteryHistoryMap.size(), (System.currentTimeMillis() - start)));
Log.d(
TAG,
String.format(
"getBatterySinceLastFullChargeUsageData() size=%d time=%d/ms",
batteryHistoryMap.size(), (System.currentTimeMillis() - start)));
final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageData =
DataProcessor.getBatteryUsageData(context, batteryHistoryMap);
if (batteryUsageData == null) {
return null;
}
BatteryDiffData allBatteryDiffData = batteryUsageData.get(
BatteryChartViewModel.SELECTED_INDEX_ALL).get(
BatteryChartViewModel.SELECTED_INDEX_ALL);
BatteryDiffData allBatteryDiffData =
batteryUsageData
.get(BatteryChartViewModel.SELECTED_INDEX_ALL)
.get(BatteryChartViewModel.SELECTED_INDEX_ALL);
return allBatteryDiffData == null ? null : allBatteryDiffData.getAppDiffEntryList();
}
@@ -546,23 +573,23 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
return null;
}
private final class DailyChartLabelTextGenerator implements
BatteryChartViewModel.LabelTextGenerator {
private final class DailyChartLabelTextGenerator
implements BatteryChartViewModel.LabelTextGenerator {
@Override
public String generateText(List<Long> timestamps, int index) {
return ConvertUtils.utcToLocalTimeDayOfWeek(mContext,
timestamps.get(index), /* isAbbreviation= */ true);
return ConvertUtils.utcToLocalTimeDayOfWeek(
mContext, timestamps.get(index), /* isAbbreviation= */ true);
}
@Override
public String generateFullText(List<Long> timestamps, int index) {
return ConvertUtils.utcToLocalTimeDayOfWeek(mContext,
timestamps.get(index), /* isAbbreviation= */ false);
return ConvertUtils.utcToLocalTimeDayOfWeek(
mContext, timestamps.get(index), /* isAbbreviation= */ false);
}
}
private final class HourlyChartLabelTextGenerator implements
BatteryChartViewModel.LabelTextGenerator {
private final class HourlyChartLabelTextGenerator
implements BatteryChartViewModel.LabelTextGenerator {
private static final int FULL_CHARGE_BATTERY_LEVEL = 100;
private boolean mIsFromFullCharge;
@@ -593,8 +620,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
public String generateFullText(List<Long> timestamps, int index) {
return index == timestamps.size() - 1
? generateText(timestamps, index)
: mContext.getString(R.string.battery_usage_timestamps_hyphen,
generateText(timestamps, index), generateText(timestamps, index + 1));
: mContext.getString(
R.string.battery_usage_timestamps_hyphen,
generateText(timestamps, index),
generateText(timestamps, index + 1));
}
HourlyChartLabelTextGenerator updateSpecialCaseContext(
@@ -604,8 +633,10 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
this.mIsFromFullCharge =
firstDayLevelData.getLevels().get(0) == FULL_CHARGE_BATTERY_LEVEL;
this.mFistTimestamp = firstDayLevelData.getTimestamps().get(0);
this.mLatestTimestamp = getLast(getLast(
batteryLevelData.getHourlyBatteryLevelsPerDay()).getTimestamps());
this.mLatestTimestamp =
getLast(
getLast(batteryLevelData.getHourlyBatteryLevelsPerDay())
.getTimestamps());
return this;
}
}

View File

@@ -74,7 +74,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
private final String[] mPercentages = getPercentages();
private final Rect mIndent = new Rect();
private final Rect[] mPercentageBounds = new Rect[]{new Rect(), new Rect(), new Rect()};
private final Rect[] mPercentageBounds = new Rect[] {new Rect(), new Rect(), new Rect()};
private final List<Rect> mAxisLabelsBounds = new ArrayList<>();
private final Set<Integer> mLabelDrawnIndexes = new ArraySet<>();
private final int mLayoutDirection =
@@ -106,11 +106,9 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
private AccessibilityNodeProvider mAccessibilityNodeProvider;
private BatteryChartView.OnSelectListener mOnSelectListener;
@VisibleForTesting
TrapezoidSlot[] mTrapezoidSlots;
@VisibleForTesting TrapezoidSlot[] mTrapezoidSlots;
// Records the location to calculate selected index.
@VisibleForTesting
float mTouchUpEventX = Float.MIN_VALUE;
@VisibleForTesting float mTouchUpEventX = Float.MIN_VALUE;
public BatteryChartView(Context context) {
super(context, null);
@@ -133,9 +131,13 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
return;
}
Log.d(TAG, String.format(
"setViewModel(): size: %d, selectedIndex: %d, getHighlightSlotIndex: %d",
viewModel.size(), viewModel.selectedIndex(), viewModel.getHighlightSlotIndex()));
Log.d(
TAG,
String.format(
"setViewModel(): size: %d, selectedIndex: %d, getHighlightSlotIndex: %d",
viewModel.size(),
viewModel.selectedIndex(),
viewModel.getHighlightSlotIndex()));
mViewModel = viewModel;
initializeAxisLabelsBounds();
initializeTrapezoidSlots(viewModel.size() - 1);
@@ -169,7 +171,9 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
mTextPaint.setTextAlign(Paint.Align.LEFT);
for (int index = 0; index < mPercentages.length; index++) {
mTextPaint.getTextBounds(
mPercentages[index], 0, mPercentages[index].length(),
mPercentages[index],
0,
mPercentages[index].length(),
mPercentageBounds[index]);
}
// Updates the indent configurations.
@@ -292,7 +296,8 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
// Selects all if users click the same trapezoid item two times.
mOnSelectListener.onSelect(
index == mViewModel.selectedIndex()
? BatteryChartViewModel.SELECTED_INDEX_ALL : index);
? BatteryChartViewModel.SELECTED_INDEX_ALL
: index);
}
view.performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK);
}
@@ -327,8 +332,9 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
setBackgroundColor(Color.TRANSPARENT);
mTrapezoidSolidColor = Utils.getColorAccentDefaultColor(context);
mTrapezoidColor = Utils.getDisabled(context, mTrapezoidSolidColor);
mTrapezoidHoverColor = Utils.getColorAttrDefaultColor(context,
com.android.internal.R.attr.materialColorSecondaryContainer);
mTrapezoidHoverColor =
Utils.getColorAttrDefaultColor(
context, com.android.internal.R.attr.materialColorSecondaryContainer);
// Initializes the divider line paint.
final Resources resources = getContext().getResources();
mDividerWidth = resources.getDimensionPixelSize(R.dimen.chartview_divider_width);
@@ -353,25 +359,26 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
// Initializes for drawing text information.
mTextPadding = resources.getDimensionPixelSize(R.dimen.chartview_text_padding);
// Initializes the padding top for drawing text information.
mTransomViewHeight = resources.getDimensionPixelSize(
R.dimen.chartview_transom_layout_height);
mTransomViewHeight =
resources.getDimensionPixelSize(R.dimen.chartview_transom_layout_height);
}
private void initializeTransomPaint() {
if (mTransomLinePaint != null && mTransomSelectedSlotPaint != null
if (mTransomLinePaint != null
&& mTransomSelectedSlotPaint != null
&& mTransomIcon != null) {
return;
}
// Initializes the transom line paint.
final Resources resources = getContext().getResources();
final int transomLineWidth = resources.getDimensionPixelSize(
R.dimen.chartview_transom_width);
final int transomLineWidth =
resources.getDimensionPixelSize(R.dimen.chartview_transom_width);
final int transomRadius = resources.getDimensionPixelSize(R.dimen.chartview_transom_radius);
mTransomPadding = transomRadius * .5f;
mTransomTop = resources.getDimensionPixelSize(R.dimen.chartview_transom_padding_top);
mTransomLineDefaultColor = Utils.getDisabled(mContext, DIVIDER_COLOR);
mTransomLineSelectedColor = resources.getColor(
R.color.color_battery_anomaly_yellow_selector);
mTransomLineSelectedColor =
resources.getColor(R.color.color_battery_anomaly_yellow_selector);
final int slotHighlightColor = Utils.getDisabled(mContext, mTransomLineSelectedColor);
mTransomIconSize = resources.getDimensionPixelSize(R.dimen.chartview_transom_icon_size);
mTransomLinePaint = new Paint();
@@ -396,18 +403,16 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
final float availableSpace = bottomOffsetY - topOffsetY;
mDividerPaint.setColor(DIVIDER_COLOR);
final float dividerOffsetUnit =
availableSpace / (float) (HORIZONTAL_DIVIDER_COUNT - 1);
final float dividerOffsetUnit = availableSpace / (float) (HORIZONTAL_DIVIDER_COUNT - 1);
// Draws 5 divider lines.
for (int index = 0; index < HORIZONTAL_DIVIDER_COUNT; index++) {
float offsetY = topOffsetY + dividerOffsetUnit * index;
canvas.drawLine(mIndent.left, offsetY,
mIndent.left + width, offsetY, mDividerPaint);
canvas.drawLine(mIndent.left, offsetY, mIndent.left + width, offsetY, mDividerPaint);
// Draws percentage text only for 100% / 50% / 0%
if (index % 2 == 0) {
drawPercentage(canvas, /*index=*/ (index + 1) / 2, offsetY);
drawPercentage(canvas, /* index= */ (index + 1) / 2, offsetY);
}
}
}
@@ -438,21 +443,23 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
Rect[] axisLabelDisplayAreas;
switch (mViewModel.axisLabelPosition()) {
case CENTER_OF_TRAPEZOIDS:
axisLabelDisplayAreas = getAxisLabelDisplayAreas(
/* size= */ mViewModel.size() - 1,
/* baselineX= */ mIndent.left + mDividerWidth + unitWidth * .5f,
/* offsetX= */ mDividerWidth + unitWidth,
baselineY,
/* shiftFirstAndLast= */ false);
axisLabelDisplayAreas =
getAxisLabelDisplayAreas(
/* size= */ mViewModel.size() - 1,
/* baselineX= */ mIndent.left + mDividerWidth + unitWidth * .5f,
/* offsetX= */ mDividerWidth + unitWidth,
baselineY,
/* shiftFirstAndLast= */ false);
break;
case BETWEEN_TRAPEZOIDS:
default:
axisLabelDisplayAreas = getAxisLabelDisplayAreas(
/* size= */ mViewModel.size(),
/* baselineX= */ mIndent.left + mDividerWidth * .5f,
/* offsetX= */ mDividerWidth + unitWidth,
baselineY,
/* shiftFirstAndLast= */ true);
axisLabelDisplayAreas =
getAxisLabelDisplayAreas(
/* size= */ mViewModel.size(),
/* baselineX= */ mIndent.left + mDividerWidth * .5f,
/* offsetX= */ mDividerWidth + unitWidth,
baselineY,
/* shiftFirstAndLast= */ true);
break;
}
drawAxisLabels(canvas, axisLabelDisplayAreas, baselineY);
@@ -481,8 +488,12 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
}
/** Gets all the axis label texts displaying area positions if they are shown. */
private Rect[] getAxisLabelDisplayAreas(final int size, final float baselineX,
final float offsetX, final float baselineY, final boolean shiftFirstAndLast) {
private Rect[] getAxisLabelDisplayAreas(
final int size,
final float baselineX,
final float offsetX,
final float baselineY,
final boolean shiftFirstAndLast) {
final Rect[] result = new Rect[size];
for (int index = 0; index < result.length; index++) {
final float width = mAxisLabelsBounds.get(index).width();
@@ -522,8 +533,11 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
* labels and then recursively draw the 3 parts. If there are any overlaps, skip drawing and go
* back to the uplevel of the recursion.
*/
private void drawAxisLabelsBetweenStartIndexAndEndIndex(Canvas canvas,
final Rect[] displayAreas, final int startIndex, final int endIndex,
private void drawAxisLabelsBetweenStartIndexAndEndIndex(
Canvas canvas,
final Rect[] displayAreas,
final int startIndex,
final int endIndex,
final float baselineY) {
if (endIndex - startIndex <= 1) {
return;
@@ -576,15 +590,12 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
mTextPaint.setTextAlign(Paint.Align.CENTER);
// Reverse the sort of axis labels for RTL
if (isRTL()) {
index = mViewModel.axisLabelPosition() == BETWEEN_TRAPEZOIDS
? mViewModel.size() - index - 1 // for hourly
: mViewModel.size() - index - 2; // for daily
index =
mViewModel.axisLabelPosition() == BETWEEN_TRAPEZOIDS
? mViewModel.size() - index - 1 // for hourly
: mViewModel.size() - index - 2; // for daily
}
canvas.drawText(
mViewModel.getText(index),
displayArea.centerX(),
baselineY,
mTextPaint);
canvas.drawText(mViewModel.getText(index), displayArea.centerX(), baselineY, mTextPaint);
mLabelDrawnIndexes.add(index);
}
@@ -594,8 +605,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
return;
}
final float trapezoidBottom =
getHeight() - mIndent.bottom - mDividerHeight - mDividerWidth
- mTrapezoidVOffset;
getHeight() - mIndent.bottom - mDividerHeight - mDividerWidth - mTrapezoidVOffset;
final float availableSpace =
trapezoidBottom - mDividerWidth * .5f - mIndent.top - mTrapezoidVOffset;
final float unitHeight = availableSpace / 100f;
@@ -608,17 +618,24 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
continue;
}
// Configures the trapezoid paint color.
final int trapezoidColor = (mViewModel.selectedIndex() == index
|| mViewModel.selectedIndex() == BatteryChartViewModel.SELECTED_INDEX_ALL)
? mTrapezoidSolidColor : mTrapezoidColor;
final boolean isHoverState = mHoveredIndex == index && isValidToDraw(mViewModel,
mHoveredIndex);
final int trapezoidColor =
(mViewModel.selectedIndex() == index
|| mViewModel.selectedIndex()
== BatteryChartViewModel.SELECTED_INDEX_ALL)
? mTrapezoidSolidColor
: mTrapezoidColor;
final boolean isHoverState =
mHoveredIndex == index && isValidToDraw(mViewModel, mHoveredIndex);
mTrapezoidPaint.setColor(isHoverState ? mTrapezoidHoverColor : trapezoidColor);
float leftTop = round(
trapezoidBottom - requireNonNull(mViewModel.getLevel(index)) * unitHeight);
float rightTop = round(trapezoidBottom
- requireNonNull(mViewModel.getLevel(index + 1)) * unitHeight);
float leftTop =
round(
trapezoidBottom
- requireNonNull(mViewModel.getLevel(index)) * unitHeight);
float rightTop =
round(
trapezoidBottom
- requireNonNull(mViewModel.getLevel(index + 1)) * unitHeight);
// Mirror the shape of the trapezoid for RTL
if (isRTL()) {
float temp = leftTop;
@@ -639,8 +656,9 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
}
private boolean isHighlightSlotValid() {
return mViewModel != null && mViewModel.getHighlightSlotIndex()
!= BatteryChartViewModel.SELECTED_INDEX_INVALID;
return mViewModel != null
&& mViewModel.getHighlightSlotIndex()
!= BatteryChartViewModel.SELECTED_INDEX_INVALID;
}
private void drawTransomLine(Canvas canvas) {
@@ -652,10 +670,13 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
mTransomLinePaint.setColor(mTransomLineDefaultColor);
final int width = getWidth() - abs(mIndent.width());
final float transomOffset = mTrapezoidHOffset + mDividerWidth * .5f + mTransomPadding;
final float trapezoidBottom = getHeight() - mIndent.bottom - mDividerHeight - mDividerWidth
- mTrapezoidVOffset;
canvas.drawLine(mIndent.left + transomOffset, mTransomTop,
mIndent.left + width - transomOffset, mTransomTop,
final float trapezoidBottom =
getHeight() - mIndent.bottom - mDividerHeight - mDividerWidth - mTrapezoidVOffset;
canvas.drawLine(
mIndent.left + transomOffset,
mTransomTop,
mIndent.left + width - transomOffset,
mTransomTop,
mTransomLinePaint);
drawTransomIcon(canvas);
// Draw selected segment of transom line and a highlight slot
@@ -663,22 +684,28 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
final int index = mViewModel.getHighlightSlotIndex();
final float startX = mTrapezoidSlots[index].mLeft;
final float endX = mTrapezoidSlots[index].mRight;
canvas.drawLine(startX + mTransomPadding, mTransomTop,
endX - mTransomPadding, mTransomTop,
canvas.drawLine(
startX + mTransomPadding,
mTransomTop,
endX - mTransomPadding,
mTransomTop,
mTransomLinePaint);
canvas.drawRect(startX, mTransomTop, endX, trapezoidBottom,
mTransomSelectedSlotPaint);
canvas.drawRect(startX, mTransomTop, endX, trapezoidBottom, mTransomSelectedSlotPaint);
}
private void drawTransomIcon(Canvas canvas) {
if (mTransomIcon == null) {
return;
}
final int left = isRTL()
? mIndent.left - mTextPadding - mTransomIconSize
: getWidth() - abs(mIndent.width()) + mTextPadding;
mTransomIcon.setBounds(left, mTransomTop - mTransomIconSize / 2,
left + mTransomIconSize, mTransomTop + mTransomIconSize / 2);
final int left =
isRTL()
? mIndent.left - mTextPadding - mTransomIconSize
: getWidth() - abs(mIndent.width()) + mTextPadding;
mTransomIcon.setBounds(
left,
mTransomTop - mTransomIconSize / 2,
left + mTransomIconSize,
mTransomTop + mTransomIconSize / 2);
mTransomIcon.draw(canvas);
}
@@ -689,8 +716,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
}
for (int index = 0; index < mTrapezoidSlots.length; index++) {
final TrapezoidSlot slot = mTrapezoidSlots[index];
if (x >= slot.mLeft - mTrapezoidHOffset
&& x <= slot.mRight + mTrapezoidHOffset) {
if (x >= slot.mLeft - mTrapezoidHOffset && x <= slot.mRight + mTrapezoidHOffset) {
return index;
}
}
@@ -712,9 +738,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
private static boolean isTrapezoidIndexValid(
@NonNull BatteryChartViewModel viewModel, int trapezoidIndex) {
return viewModel != null
&& trapezoidIndex >= 0
&& trapezoidIndex < viewModel.size() - 1;
return viewModel != null && trapezoidIndex >= 0 && trapezoidIndex < viewModel.size() - 1;
}
private static boolean isValidToDraw(BatteryChartViewModel viewModel, int trapezoidIndex) {
@@ -733,10 +757,11 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
}
private static String[] getPercentages() {
return new String[]{
formatPercentage(/*percentage=*/ 100, /*round=*/ true),
formatPercentage(/*percentage=*/ 50, /*round=*/ true),
formatPercentage(/*percentage=*/ 0, /*round=*/ true)};
return new String[] {
formatPercentage(/* percentage= */ 100, /* round= */ true),
formatPercentage(/* percentage= */ 50, /* round= */ true),
formatPercentage(/* percentage= */ 0, /* round= */ true)
};
}
private class BatteryChartAccessibilityNodeProvider extends AccessibilityNodeProvider {
@@ -772,8 +797,7 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
}
@Override
public boolean performAction(int virtualViewId, int action,
@Nullable Bundle arguments) {
public boolean performAction(int virtualViewId, int action, @Nullable Bundle arguments) {
if (virtualViewId == AccessibilityNodeProvider.HOST_VIEW_ID) {
return performAccessibilityAction(action, arguments);
}
@@ -783,11 +807,12 @@ public class BatteryChartView extends AppCompatImageView implements View.OnClick
return true;
case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS:
return sendAccessibilityEvent(virtualViewId,
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
return sendAccessibilityEvent(
virtualViewId, AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS:
return sendAccessibilityEvent(virtualViewId,
return sendAccessibilityEvent(
virtualViewId,
AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
default:

View File

@@ -57,14 +57,18 @@ class BatteryChartViewModel {
private int mSelectedIndex = SELECTED_INDEX_ALL;
private int mHighlightSlotIndex = SELECTED_INDEX_INVALID;
BatteryChartViewModel(@NonNull List<Integer> levels, @NonNull List<Long> timestamps,
BatteryChartViewModel(
@NonNull List<Integer> levels,
@NonNull List<Long> timestamps,
@NonNull AxisLabelPosition axisLabelPosition,
@NonNull LabelTextGenerator labelTextGenerator) {
Preconditions.checkArgument(
levels.size() == timestamps.size() && levels.size() >= MIN_LEVELS_DATA_SIZE,
String.format(Locale.ENGLISH,
String.format(
Locale.ENGLISH,
"Invalid BatteryChartViewModel levels.size: %d, timestamps.size: %d.",
levels.size(), timestamps.size()));
levels.size(),
timestamps.size()));
mLevels = levels;
mTimestamps = timestamps;
mAxisLabelPosition = axisLabelPosition;

View File

@@ -64,8 +64,7 @@ public class BatteryDiffEntry {
private static final Map<String, Pair<Integer, Integer>> SPECIAL_ENTRY_MAP =
Map.of(
SYSTEM_APPS_KEY,
Pair.create(
R.string.battery_usage_system_apps, R.drawable.ic_power_system),
Pair.create(R.string.battery_usage_system_apps, R.drawable.ic_power_system),
UNINSTALLED_APPS_KEY,
Pair.create(
R.string.battery_usage_uninstalled_apps,
@@ -100,16 +99,11 @@ public class BatteryDiffEntry {
private UserManager mUserManager;
private String mDefaultPackageName = null;
@VisibleForTesting
int mAppIconId;
@VisibleForTesting
String mAppLabel = null;
@VisibleForTesting
Drawable mAppIcon = null;
@VisibleForTesting
boolean mIsLoaded = false;
@VisibleForTesting
boolean mValidForRestriction = true;
@VisibleForTesting int mAppIconId;
@VisibleForTesting String mAppLabel = null;
@VisibleForTesting Drawable mAppIcon = null;
@VisibleForTesting boolean mIsLoaded = false;
@VisibleForTesting boolean mValidForRestriction = true;
public BatteryDiffEntry(
Context context,
@@ -150,12 +144,24 @@ public class BatteryDiffEntry {
}
public BatteryDiffEntry(Context context, String key, String legacyLabel, int consumerType) {
this(context, /*uid=*/ 0, /*userId=*/ 0, key, /*isHidden=*/ false, /*componentId=*/ -1,
/*legacyPackageName=*/ null, legacyLabel, consumerType,
/*foregroundUsageTimeInMs=*/ 0, /*backgroundUsageTimeInMs=*/ 0,
/*screenOnTimeInMs=*/ 0, /*consumePower=*/ 0, /*foregroundUsageConsumePower=*/ 0,
/*foregroundServiceUsageConsumePower=*/ 0, /*backgroundUsageConsumePower=*/ 0,
/*cachedUsageConsumePower=*/ 0);
this(
context,
/* uid= */ 0,
/* userId= */ 0,
key,
/* isHidden= */ false,
/* componentId= */ -1,
/* legacyPackageName= */ null,
legacyLabel,
consumerType,
/* foregroundUsageTimeInMs= */ 0,
/* backgroundUsageTimeInMs= */ 0,
/* screenOnTimeInMs= */ 0,
/* consumePower= */ 0,
/* foregroundUsageConsumePower= */ 0,
/* foregroundServiceUsageConsumePower= */ 0,
/* backgroundUsageConsumePower= */ 0,
/* cachedUsageConsumePower= */ 0);
}
/** Sets the total consumed power in a specific time slot. */
@@ -286,7 +292,8 @@ public class BatteryDiffEntry {
/** Whether the current BatteryDiffEntry is uninstalled app or not. */
public boolean isUninstalledEntry() {
final String packageName = getPackageName();
if (TextUtils.isEmpty(packageName) || isSystemEntry()
if (TextUtils.isEmpty(packageName)
|| isSystemEntry()
// Some special package UIDs could be 0. Those packages are not installed by users.
|| mUid == BatteryUtils.UID_ZERO) {
return false;
@@ -468,8 +475,9 @@ public class BatteryDiffEntry {
mAppIcon = nameAndIcon.mIcon;
}
final BatteryEntry.NameAndIcon nameAndIcon = BatteryEntry.loadNameAndIcon(
mContext, uid, /*batteryEntry=*/ null, packageName, mAppLabel, mAppIcon);
final BatteryEntry.NameAndIcon nameAndIcon =
BatteryEntry.loadNameAndIcon(
mContext, uid, /* batteryEntry= */ null, packageName, mAppLabel, mAppIcon);
// Clears BatteryEntry internal cache since we will have another one.
BatteryEntry.clearUidCache();
if (nameAndIcon != null) {
@@ -489,25 +497,48 @@ public class BatteryDiffEntry {
@Override
public String toString() {
final StringBuilder builder = new StringBuilder()
.append("BatteryDiffEntry{")
.append(String.format("\n\tname=%s restrictable=%b",
mAppLabel, mValidForRestriction))
.append(String.format("\n\tconsume=%.2f%% %f/%f",
mPercentage, mConsumePower, mTotalConsumePower))
.append(String.format("\n\tconsume power= foreground:%f foregroundService:%f",
mForegroundUsageConsumePower, mForegroundServiceUsageConsumePower))
.append(String.format("\n\tconsume power= background:%f cached:%f",
mBackgroundUsageConsumePower, mCachedUsageConsumePower))
.append(String.format("\n\ttime= foreground:%s background:%s screen-on:%s",
StringUtil.formatElapsedTime(mContext, (double) mForegroundUsageTimeInMs,
/*withSeconds=*/ true, /*collapseTimeUnit=*/ false),
StringUtil.formatElapsedTime(mContext, (double) mBackgroundUsageTimeInMs,
/*withSeconds=*/ true, /*collapseTimeUnit=*/ false),
StringUtil.formatElapsedTime(mContext, (double) mScreenOnTimeInMs,
/*withSeconds=*/ true, /*collapseTimeUnit=*/ false)))
.append(String.format("\n\tpackage:%s|%s uid:%d userId:%d",
mLegacyPackageName, getPackageName(), mUid, mUserId));
final StringBuilder builder =
new StringBuilder()
.append("BatteryDiffEntry{")
.append(
String.format(
"\n\tname=%s restrictable=%b",
mAppLabel, mValidForRestriction))
.append(
String.format(
"\n\tconsume=%.2f%% %f/%f",
mPercentage, mConsumePower, mTotalConsumePower))
.append(
String.format(
"\n\tconsume power= foreground:%f foregroundService:%f",
mForegroundUsageConsumePower,
mForegroundServiceUsageConsumePower))
.append(
String.format(
"\n\tconsume power= background:%f cached:%f",
mBackgroundUsageConsumePower, mCachedUsageConsumePower))
.append(
String.format(
"\n\ttime= foreground:%s background:%s screen-on:%s",
StringUtil.formatElapsedTime(
mContext,
(double) mForegroundUsageTimeInMs,
/* withSeconds= */ true,
/* collapseTimeUnit= */ false),
StringUtil.formatElapsedTime(
mContext,
(double) mBackgroundUsageTimeInMs,
/* withSeconds= */ true,
/* collapseTimeUnit= */ false),
StringUtil.formatElapsedTime(
mContext,
(double) mScreenOnTimeInMs,
/* withSeconds= */ true,
/* collapseTimeUnit= */ false)))
.append(
String.format(
"\n\tpackage:%s|%s uid:%d userId:%d",
mLegacyPackageName, getPackageName(), mUid, mUserId));
return builder.toString();
}

View File

@@ -45,8 +45,7 @@ import java.util.Comparator;
import java.util.Locale;
/**
* Wraps the power usage data of a BatterySipper with information about package name
* and icon image.
* Wraps the power usage data of a BatterySipper with information about package name and icon image.
*/
public class BatteryEntry {
@@ -58,11 +57,10 @@ public class BatteryEntry {
public final int mIconId;
public NameAndIcon(String name, Drawable icon, int iconId) {
this(name, /*packageName=*/ null, icon, iconId);
this(name, /* packageName= */ null, icon, iconId);
}
public NameAndIcon(
String name, String packageName, Drawable icon, int iconId) {
public NameAndIcon(String name, String packageName, Drawable icon, int iconId) {
this.mName = name;
this.mIcon = icon;
this.mIconId = iconId;
@@ -78,17 +76,20 @@ public class BatteryEntry {
static final int BATTERY_USAGE_INDEX_BACKGROUND = 2;
static final int BATTERY_USAGE_INDEX_CACHED = 3;
static final Dimensions[] BATTERY_DIMENSIONS = new Dimensions[] {
new Dimensions(
BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_FOREGROUND),
new Dimensions(
BatteryConsumer.POWER_COMPONENT_ANY,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE),
new Dimensions(
BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_BACKGROUND),
new Dimensions(
BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_CACHED),
};
static final Dimensions[] BATTERY_DIMENSIONS =
new Dimensions[] {
new Dimensions(
BatteryConsumer.POWER_COMPONENT_ANY,
BatteryConsumer.PROCESS_STATE_FOREGROUND),
new Dimensions(
BatteryConsumer.POWER_COMPONENT_ANY,
BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE),
new Dimensions(
BatteryConsumer.POWER_COMPONENT_ANY,
BatteryConsumer.PROCESS_STATE_BACKGROUND),
new Dimensions(
BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_CACHED),
};
static final ArrayMap<String, UidToDetail> sUidCache = new ArrayMap<>();
@@ -106,10 +107,8 @@ public class BatteryEntry {
private final BatteryConsumer mBatteryConsumer;
private final int mUid;
private final boolean mIsHidden;
@ConvertUtils.ConsumerType
private final int mConsumerType;
@BatteryConsumer.PowerComponent
private final int mPowerComponentId;
@ConvertUtils.ConsumerType private final int mConsumerType;
@BatteryConsumer.PowerComponent private final int mPowerComponentId;
private long mUsageDurationMs;
private long mTimeInForegroundMs;
private long mTimeInBackgroundMs;
@@ -131,13 +130,25 @@ public class BatteryEntry {
Drawable mIcon;
}
public BatteryEntry(Context context, UserManager um, BatteryConsumer batteryConsumer,
boolean isHidden, int uid, String[] packages, String packageName) {
public BatteryEntry(
Context context,
UserManager um,
BatteryConsumer batteryConsumer,
boolean isHidden,
int uid,
String[] packages,
String packageName) {
this(context, um, batteryConsumer, isHidden, uid, packages, packageName, true);
}
public BatteryEntry(Context context, UserManager um, BatteryConsumer batteryConsumer,
boolean isHidden, int uid, String[] packages, String packageName,
public BatteryEntry(
Context context,
UserManager um,
BatteryConsumer batteryConsumer,
boolean isHidden,
int uid,
String[] packages,
String packageName,
boolean loadDataInBackground) {
mContext = context;
mBatteryConsumer = batteryConsumer;
@@ -156,8 +167,10 @@ public class BatteryEntry {
if (packages != null && packages.length == 1) {
mDefaultPackageName = packages[0];
} else {
mDefaultPackageName = isSystemUid(uid)
? PACKAGE_SYSTEM : uidBatteryConsumer.getPackageWithHighestDrain();
mDefaultPackageName =
isSystemUid(uid)
? PACKAGE_SYSTEM
: uidBatteryConsumer.getPackageWithHighestDrain();
}
}
if (mDefaultPackageName != null) {
@@ -167,8 +180,10 @@ public class BatteryEntry {
pm.getApplicationInfo(mDefaultPackageName, 0 /* no flags */);
mName = pm.getApplicationLabel(appInfo).toString();
} catch (NameNotFoundException e) {
Log.d(TAG, "PackageManager failed to retrieve ApplicationInfo for: "
+ mDefaultPackageName);
Log.d(
TAG,
"PackageManager failed to retrieve ApplicationInfo for: "
+ mDefaultPackageName);
mName = mDefaultPackageName;
}
}
@@ -176,20 +191,26 @@ public class BatteryEntry {
uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND);
mTimeInBackgroundMs =
uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND);
mConsumedPowerInForeground = safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND]);
mConsumedPowerInForegroundService = safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
mConsumedPowerInBackground = safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_BACKGROUND]);
mConsumedPowerInCached = safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_CACHED]);
mConsumedPowerInForeground =
safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND]);
mConsumedPowerInForegroundService =
safeGetConsumedPower(
uidBatteryConsumer,
BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
mConsumedPowerInBackground =
safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_BACKGROUND]);
mConsumedPowerInCached =
safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_CACHED]);
} else if (batteryConsumer instanceof UserBatteryConsumer) {
mUid = Process.INVALID_UID;
mConsumerType = ConvertUtils.CONSUMER_TYPE_USER_BATTERY;
mConsumedPower = batteryConsumer.getConsumedPower();
final NameAndIcon nameAndIcon = getNameAndIconFromUserId(
context, ((UserBatteryConsumer) batteryConsumer).getUserId());
final NameAndIcon nameAndIcon =
getNameAndIconFromUserId(
context, ((UserBatteryConsumer) batteryConsumer).getUserId());
mIcon = nameAndIcon.mIcon;
mName = nameAndIcon.mName;
} else {
@@ -198,8 +219,12 @@ public class BatteryEntry {
}
/** Battery entry for a power component of AggregateBatteryConsumer */
public BatteryEntry(Context context, int powerComponentId, double devicePowerMah,
long usageDurationMs, boolean isHidden) {
public BatteryEntry(
Context context,
int powerComponentId,
double devicePowerMah,
long usageDurationMs,
boolean isHidden) {
mContext = context;
mBatteryConsumer = null;
mUid = Process.INVALID_UID;
@@ -209,8 +234,7 @@ public class BatteryEntry {
mUsageDurationMs = usageDurationMs;
mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY;
final NameAndIcon nameAndIcon =
getNameAndIconFromPowerComponent(context, powerComponentId);
final NameAndIcon nameAndIcon = getNameAndIconFromPowerComponent(context, powerComponentId);
mIconId = nameAndIcon.mIconId;
mName = nameAndIcon.mName;
if (mIconId != 0) {
@@ -219,7 +243,10 @@ public class BatteryEntry {
}
/** Battery entry for a custom power component of AggregateBatteryConsumer */
public BatteryEntry(Context context, int powerComponentId, String powerComponentName,
public BatteryEntry(
Context context,
int powerComponentId,
String powerComponentName,
double devicePowerMah) {
mContext = context;
mBatteryConsumer = null;
@@ -266,8 +293,8 @@ public class BatteryEntry {
}
final PackageManager pm = context.getPackageManager();
final String[] packages = isSystemUid(uid)
? new String[]{PACKAGE_SYSTEM} : pm.getPackagesForUid(uid);
final String[] packages =
isSystemUid(uid) ? new String[] {PACKAGE_SYSTEM} : pm.getPackagesForUid(uid);
if (packages != null) {
final String[] packageLabels = new String[packages.length];
System.arraycopy(packages, 0, packageLabels, 0, packages.length);
@@ -277,11 +304,15 @@ public class BatteryEntry {
final int userId = UserHandle.getUserId(uid);
for (int i = 0; i < packageLabels.length; i++) {
try {
final ApplicationInfo ai = ipm.getApplicationInfo(packageLabels[i],
0 /* no flags */, userId);
final ApplicationInfo ai =
ipm.getApplicationInfo(packageLabels[i], 0 /* no flags */, userId);
if (ai == null) {
Log.d(TAG, "Retrieving null app info for package "
+ packageLabels[i] + ", user " + userId);
Log.d(
TAG,
"Retrieving null app info for package "
+ packageLabels[i]
+ ", user "
+ userId);
continue;
}
final CharSequence label = ai.loadLabel(pm);
@@ -294,8 +325,13 @@ public class BatteryEntry {
break;
}
} catch (RemoteException e) {
Log.d(TAG, "Error while retrieving app info for package "
+ packageLabels[i] + ", user " + userId, e);
Log.d(
TAG,
"Error while retrieving app info for package "
+ packageLabels[i]
+ ", user "
+ userId,
e);
}
}
@@ -307,13 +343,17 @@ public class BatteryEntry {
try {
final PackageInfo pi = ipm.getPackageInfo(pkgName, 0, userId);
if (pi == null) {
Log.d(TAG, "Retrieving null package info for package "
+ pkgName + ", user " + userId);
Log.d(
TAG,
"Retrieving null package info for package "
+ pkgName
+ ", user "
+ userId);
continue;
}
if (pi.sharedUserLabel != 0) {
final CharSequence nm = pm.getText(pkgName,
pi.sharedUserLabel, pi.applicationInfo);
final CharSequence nm =
pm.getText(pkgName, pi.sharedUserLabel, pi.applicationInfo);
if (nm != null) {
name = nm.toString();
if (pi.applicationInfo.icon != 0) {
@@ -324,8 +364,13 @@ public class BatteryEntry {
}
}
} catch (RemoteException e) {
Log.d(TAG, "Error while retrieving package info for package "
+ pkgName + ", user " + userId, e);
Log.d(
TAG,
"Error while retrieving package info for package "
+ pkgName
+ ", user "
+ userId,
e);
}
}
}
@@ -342,7 +387,7 @@ public class BatteryEntry {
utd.mPackageName = defaultPackageName;
sUidCache.put(uidString, utd);
return new NameAndIcon(name, defaultPackageName, icon, /*iconId=*/ 0);
return new NameAndIcon(name, defaultPackageName, icon, /* iconId= */ 0);
}
/** Returns a string that uniquely identifies this battery consumer. */
@@ -375,16 +420,13 @@ public class BatteryEntry {
}
/**
* Returns the package name that should be used to represent the UID described
* by this entry.
* Returns the package name that should be used to represent the UID described by this entry.
*/
public String getDefaultPackageName() {
return mDefaultPackageName;
}
/**
* Returns the UID of the app described by this entry.
*/
/** Returns the UID of the app described by this entry. */
public int getUid() {
return mUid;
}
@@ -407,9 +449,7 @@ public class BatteryEntry {
}
}
/**
* Returns total amount of power (in milli-amp-hours) that is attributed to this entry.
*/
/** Returns total amount of power (in milli-amp-hours) that is attributed to this entry. */
public double getConsumedPower() {
return mConsumedPower;
}
@@ -462,25 +502,30 @@ public class BatteryEntry {
}
/**
* Adds the consumed power of the supplied BatteryConsumer to this entry. Also
* uses its package with highest drain, if necessary.
* Adds the consumed power of the supplied BatteryConsumer to this entry. Also uses its package
* with highest drain, if necessary.
*/
public void add(BatteryConsumer batteryConsumer) {
mConsumedPower += batteryConsumer.getConsumedPower();
if (batteryConsumer instanceof UidBatteryConsumer) {
UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer;
mTimeInForegroundMs += uidBatteryConsumer.getTimeInStateMs(
UidBatteryConsumer.STATE_FOREGROUND);
mTimeInBackgroundMs += uidBatteryConsumer.getTimeInStateMs(
UidBatteryConsumer.STATE_BACKGROUND);
mConsumedPowerInForeground += safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND]);
mConsumedPowerInForegroundService += safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
mConsumedPowerInBackground += safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_BACKGROUND]);
mConsumedPowerInCached += safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_CACHED]);
mTimeInForegroundMs +=
uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND);
mTimeInBackgroundMs +=
uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND);
mConsumedPowerInForeground +=
safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND]);
mConsumedPowerInForegroundService +=
safeGetConsumedPower(
uidBatteryConsumer,
BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]);
mConsumedPowerInBackground +=
safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_BACKGROUND]);
mConsumedPowerInCached +=
safeGetConsumedPower(
uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_CACHED]);
if (mDefaultPackageName == null) {
mDefaultPackageName = uidBatteryConsumer.getPackageWithHighestDrain();
}
@@ -488,8 +533,7 @@ public class BatteryEntry {
}
/** Gets name and icon resource from UserBatteryConsumer userId. */
public static NameAndIcon getNameAndIconFromUserId(
Context context, final int userId) {
public static NameAndIcon getNameAndIconFromUserId(Context context, final int userId) {
UserManager um = context.getSystemService(UserManager.class);
UserInfo info = um.getUserInfo(userId);
@@ -499,27 +543,27 @@ public class BatteryEntry {
icon = Utils.getUserIcon(context, um, info);
name = Utils.getUserLabel(context, info);
} else {
name = context.getResources().getString(
R.string.running_process_item_removed_user_label);
name =
context.getResources()
.getString(R.string.running_process_item_removed_user_label);
}
return new NameAndIcon(name, icon, 0 /* iconId */);
}
/** Gets name and icon resource from UidBatteryConsumer uid. */
public static NameAndIcon getNameAndIconFromUid(
Context context, String name, final int uid) {
public static NameAndIcon getNameAndIconFromUid(Context context, String name, final int uid) {
Drawable icon = context.getDrawable(R.drawable.ic_power_system);
if (uid == 0) {
name = context.getResources()
.getString(com.android.settingslib.R.string.process_kernel_label);
name =
context.getResources()
.getString(com.android.settingslib.R.string.process_kernel_label);
} else if (uid == BatteryUtils.UID_REMOVED_APPS) {
name = context.getResources().getString(R.string.process_removed_apps);
} else if (uid == BatteryUtils.UID_TETHERING) {
name = context.getResources().getString(R.string.process_network_tethering);
} else if ("mediaserver".equals(name)) {
name = context.getResources().getString(R.string.process_mediaserver_label);
} else if ("dex2oat".equals(name) || "dex2oat32".equals(name)
|| "dex2oat64".equals(name)) {
} else if ("dex2oat".equals(name) || "dex2oat32".equals(name) || "dex2oat64".equals(name)) {
name = context.getResources().getString(R.string.process_dex2oat_label);
}
return new NameAndIcon(name, icon, 0 /* iconId */);
@@ -531,12 +575,12 @@ public class BatteryEntry {
String name;
int iconId;
switch (powerComponentId) {
// Please see go/battery-usage-system-component-map
case BatteryConsumer.POWER_COMPONENT_SCREEN: // id: 0
// Please see go/battery-usage-system-component-map
case BatteryConsumer.POWER_COMPONENT_SCREEN: // id: 0
name = context.getResources().getString(R.string.power_screen);
iconId = R.drawable.ic_settings_display;
break;
case BatteryConsumer.POWER_COMPONENT_CPU: // id: 1
case BatteryConsumer.POWER_COMPONENT_CPU: // id: 1
name = context.getResources().getString(R.string.power_cpu);
iconId = R.drawable.ic_settings_cpu;
break;
@@ -544,11 +588,11 @@ public class BatteryEntry {
name = context.getResources().getString(R.string.power_bluetooth);
iconId = R.drawable.ic_settings_bluetooth;
break;
case BatteryConsumer.POWER_COMPONENT_CAMERA: // id: 3
case BatteryConsumer.POWER_COMPONENT_CAMERA: // id: 3
name = context.getResources().getString(R.string.power_camera);
iconId = R.drawable.ic_settings_camera;
break;
case BatteryConsumer.POWER_COMPONENT_FLASHLIGHT: // id: 6
case BatteryConsumer.POWER_COMPONENT_FLASHLIGHT: // id: 6
name = context.getResources().getString(R.string.power_flashlight);
iconId = R.drawable.ic_settings_flashlight;
break;
@@ -556,25 +600,30 @@ public class BatteryEntry {
name = context.getResources().getString(R.string.power_cell);
iconId = R.drawable.ic_settings_cellular;
break;
case BatteryConsumer.POWER_COMPONENT_GNSS: // id: 10
case BatteryConsumer.POWER_COMPONENT_GNSS: // id: 10
name = context.getResources().getString(R.string.power_gps);
iconId = R.drawable.ic_settings_gps;
break;
case BatteryConsumer.POWER_COMPONENT_WIFI: // id: 11
case BatteryConsumer.POWER_COMPONENT_WIFI: // id: 11
name = context.getResources().getString(R.string.power_wifi);
iconId = R.drawable.ic_settings_wireless_no_theme;
break;
case BatteryConsumer.POWER_COMPONENT_PHONE: // id: 14
case BatteryConsumer.POWER_COMPONENT_PHONE: // id: 14
name = context.getResources().getString(R.string.power_phone);
iconId = R.drawable.ic_settings_voice_calls;
break;
case BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY: // id :15
case BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY: // id :15
name = context.getResources().getString(R.string.ambient_display_screen_title);
iconId = R.drawable.ic_settings_aod;
break;
default:
Log.w(TAG, "unknown attribute:" + DebugUtils.constantToString(
BatteryConsumer.class, "POWER_COMPONENT_", powerComponentId));
Log.w(
TAG,
"unknown attribute:"
+ DebugUtils.constantToString(
BatteryConsumer.class,
"POWER_COMPONENT_",
powerComponentId));
name = null;
iconId = R.drawable.ic_power_system;
break;

View File

@@ -29,6 +29,7 @@ public class BatteryHistEntry {
/** Keys for accessing {@link ContentValues} or {@link Cursor}. */
public static final String KEY_UID = "uid";
public static final String KEY_USER_ID = "userId";
public static final String KEY_PACKAGE_NAME = "packageName";
public static final String KEY_TIMESTAMP = "timestamp";
@@ -57,10 +58,8 @@ public class BatteryHistEntry {
public final double mPercentOfTotal;
public final long mForegroundUsageTimeInMs;
public final long mBackgroundUsageTimeInMs;
@BatteryConsumer.PowerComponent
public final int mDrainType;
@ConvertUtils.ConsumerType
public final int mConsumerType;
@BatteryConsumer.PowerComponent public final int mDrainType;
@ConvertUtils.ConsumerType public final int mConsumerType;
// Records the battery intent relative information.
public final int mBatteryLevel;
public final int mBatteryStatus;
@@ -190,25 +189,45 @@ public class BatteryHistEntry {
@Override
public String toString() {
final String recordAtDateTime = ConvertUtils.utcToLocalTimeForLogging(mTimestamp);
final StringBuilder builder = new StringBuilder()
.append("\nBatteryHistEntry{")
.append(String.format("\n\tpackage=%s|label=%s|uid=%d|userId=%d|isHidden=%b",
mPackageName, mAppLabel, mUid, mUserId, mIsHidden))
.append(String.format("\n\ttimestamp=%s|zoneId=%s|bootTimestamp=%d",
recordAtDateTime, mZoneId, Duration.ofMillis(mBootTimestamp).getSeconds()))
.append(String.format("\n\tusage=%f|total=%f|consume=%f",
mPercentOfTotal, mTotalPower, mConsumePower))
.append(String.format("\n\tforeground=%f|foregroundService=%f",
mForegroundUsageConsumePower, mForegroundServiceUsageConsumePower))
.append(String.format("\n\tbackground=%f|cached=%f",
mBackgroundUsageConsumePower, mCachedUsageConsumePower))
.append(String.format("\n\telapsedTime=%d|%d",
Duration.ofMillis(mForegroundUsageTimeInMs).getSeconds(),
Duration.ofMillis(mBackgroundUsageTimeInMs).getSeconds()))
.append(String.format("\n\tdrainType=%d|consumerType=%d",
mDrainType, mConsumerType))
.append(String.format("\n\tbattery=%d|status=%d|health=%d\n}",
mBatteryLevel, mBatteryStatus, mBatteryHealth));
final StringBuilder builder =
new StringBuilder()
.append("\nBatteryHistEntry{")
.append(
String.format(
"\n\tpackage=%s|label=%s|uid=%d|userId=%d|isHidden=%b",
mPackageName, mAppLabel, mUid, mUserId, mIsHidden))
.append(
String.format(
"\n\ttimestamp=%s|zoneId=%s|bootTimestamp=%d",
recordAtDateTime,
mZoneId,
Duration.ofMillis(mBootTimestamp).getSeconds()))
.append(
String.format(
"\n\tusage=%f|total=%f|consume=%f",
mPercentOfTotal, mTotalPower, mConsumePower))
.append(
String.format(
"\n\tforeground=%f|foregroundService=%f",
mForegroundUsageConsumePower,
mForegroundServiceUsageConsumePower))
.append(
String.format(
"\n\tbackground=%f|cached=%f",
mBackgroundUsageConsumePower, mCachedUsageConsumePower))
.append(
String.format(
"\n\telapsedTime=%d|%d",
Duration.ofMillis(mForegroundUsageTimeInMs).getSeconds(),
Duration.ofMillis(mBackgroundUsageTimeInMs).getSeconds()))
.append(
String.format(
"\n\tdrainType=%d|consumerType=%d",
mDrainType, mConsumerType))
.append(
String.format(
"\n\tbattery=%d|status=%d|health=%d\n}",
mBatteryLevel, mBatteryStatus, mBatteryHealth));
return builder.toString();
}
@@ -270,65 +289,81 @@ public class BatteryHistEntry {
double ratio,
BatteryHistEntry lowerHistEntry,
BatteryHistEntry upperHistEntry) {
final double totalPower = interpolate(
lowerHistEntry == null ? 0 : lowerHistEntry.mTotalPower,
upperHistEntry.mTotalPower,
ratio);
final double consumePower = interpolate(
lowerHistEntry == null ? 0 : lowerHistEntry.mConsumePower,
upperHistEntry.mConsumePower,
ratio);
final double foregroundUsageConsumePower = interpolate(
lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageConsumePower,
upperHistEntry.mForegroundUsageConsumePower,
ratio);
final double foregroundServiceUsageConsumePower = interpolate(
lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundServiceUsageConsumePower,
upperHistEntry.mForegroundServiceUsageConsumePower,
ratio);
final double backgroundUsageConsumePower = interpolate(
lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageConsumePower,
upperHistEntry.mBackgroundUsageConsumePower,
ratio);
final double cachedUsageConsumePower = interpolate(
lowerHistEntry == null ? 0 : lowerHistEntry.mCachedUsageConsumePower,
upperHistEntry.mCachedUsageConsumePower,
ratio);
final double foregroundUsageTimeInMs = interpolate(
(double) (lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageTimeInMs),
(double) upperHistEntry.mForegroundUsageTimeInMs,
ratio);
final double backgroundUsageTimeInMs = interpolate(
(double) (lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageTimeInMs),
(double) upperHistEntry.mBackgroundUsageTimeInMs,
ratio);
final double totalPower =
interpolate(
lowerHistEntry == null ? 0 : lowerHistEntry.mTotalPower,
upperHistEntry.mTotalPower,
ratio);
final double consumePower =
interpolate(
lowerHistEntry == null ? 0 : lowerHistEntry.mConsumePower,
upperHistEntry.mConsumePower,
ratio);
final double foregroundUsageConsumePower =
interpolate(
lowerHistEntry == null ? 0 : lowerHistEntry.mForegroundUsageConsumePower,
upperHistEntry.mForegroundUsageConsumePower,
ratio);
final double foregroundServiceUsageConsumePower =
interpolate(
lowerHistEntry == null
? 0
: lowerHistEntry.mForegroundServiceUsageConsumePower,
upperHistEntry.mForegroundServiceUsageConsumePower,
ratio);
final double backgroundUsageConsumePower =
interpolate(
lowerHistEntry == null ? 0 : lowerHistEntry.mBackgroundUsageConsumePower,
upperHistEntry.mBackgroundUsageConsumePower,
ratio);
final double cachedUsageConsumePower =
interpolate(
lowerHistEntry == null ? 0 : lowerHistEntry.mCachedUsageConsumePower,
upperHistEntry.mCachedUsageConsumePower,
ratio);
final double foregroundUsageTimeInMs =
interpolate(
(double)
(lowerHistEntry == null
? 0
: lowerHistEntry.mForegroundUsageTimeInMs),
(double) upperHistEntry.mForegroundUsageTimeInMs,
ratio);
final double backgroundUsageTimeInMs =
interpolate(
(double)
(lowerHistEntry == null
? 0
: lowerHistEntry.mBackgroundUsageTimeInMs),
(double) upperHistEntry.mBackgroundUsageTimeInMs,
ratio);
// Checks whether there is any abnormal cases!
if (upperHistEntry.mConsumePower < consumePower
|| upperHistEntry.mForegroundUsageConsumePower < foregroundUsageConsumePower
|| upperHistEntry.mForegroundServiceUsageConsumePower
< foregroundServiceUsageConsumePower
< foregroundServiceUsageConsumePower
|| upperHistEntry.mBackgroundUsageConsumePower < backgroundUsageConsumePower
|| upperHistEntry.mCachedUsageConsumePower < cachedUsageConsumePower
|| upperHistEntry.mForegroundUsageTimeInMs < foregroundUsageTimeInMs
|| upperHistEntry.mBackgroundUsageTimeInMs < backgroundUsageTimeInMs) {
if (DEBUG) {
Log.w(TAG, String.format(
"abnormal interpolation:\nupper:%s\nlower:%s",
upperHistEntry, lowerHistEntry));
Log.w(
TAG,
String.format(
"abnormal interpolation:\nupper:%s\nlower:%s",
upperHistEntry, lowerHistEntry));
}
}
final double batteryLevel =
lowerHistEntry == null
? upperHistEntry.mBatteryLevel
: interpolate(
lowerHistEntry.mBatteryLevel,
upperHistEntry.mBatteryLevel,
ratio);
lowerHistEntry.mBatteryLevel, upperHistEntry.mBatteryLevel, ratio);
return new BatteryHistEntry(
upperHistEntry,
/*bootTimestamp=*/ upperHistEntry.mBootTimestamp
- (upperTimestamp - slotTimestamp),
/*timestamp=*/ slotTimestamp,
/* bootTimestamp= */ upperHistEntry.mBootTimestamp
- (upperTimestamp - slotTimestamp),
/* timestamp= */ slotTimestamp,
totalPower,
consumePower,
foregroundUsageConsumePower,

View File

@@ -26,9 +26,7 @@ import androidx.preference.PreferenceViewHolder;
import com.android.settings.R;
import com.android.settings.fuelgauge.BatteryUtils;
/**
* Custom preference for displaying the battery level as chart graph.
*/
/** Custom preference for displaying the battery level as chart graph. */
public class BatteryHistoryPreference extends Preference {
private static final String TAG = "BatteryHistoryPreference";

View File

@@ -47,13 +47,14 @@ public final class BatteryLevelData {
private final List<Integer> mLevels;
public PeriodBatteryLevelData(
@NonNull Map<Long, Integer> batteryLevelMap,
@NonNull List<Long> timestamps) {
@NonNull Map<Long, Integer> batteryLevelMap, @NonNull List<Long> timestamps) {
mTimestamps = timestamps;
mLevels = new ArrayList<>(timestamps.size());
for (Long timestamp : timestamps) {
mLevels.add(batteryLevelMap.containsKey(timestamp)
? batteryLevelMap.get(timestamp) : BATTERY_LEVEL_UNKNOWN);
mLevels.add(
batteryLevelMap.containsKey(timestamp)
? batteryLevelMap.get(timestamp)
: BATTERY_LEVEL_UNKNOWN);
}
}
@@ -67,8 +68,11 @@ public final class BatteryLevelData {
@Override
public String toString() {
return String.format(Locale.ENGLISH, "timestamps: %s; levels: %s",
Objects.toString(mTimestamps), Objects.toString(mLevels));
return String.format(
Locale.ENGLISH,
"timestamps: %s; levels: %s",
Objects.toString(mTimestamps),
Objects.toString(mLevels));
}
private int getIndexByTimestamps(long startTimestamp, long endTimestamp) {
@@ -83,14 +87,15 @@ public final class BatteryLevelData {
}
/**
* There could be 2 cases for the daily battery levels:
* There could be 2 cases for the daily battery levels: <br>
* 1) length is 2: The usage data is within 1 day. Only contains start and end data, such as
* data of 2022-01-01 06:00 and 2022-01-01 16:00.
* data of 2022-01-01 06:00 and 2022-01-01 16:00. <br>
* 2) length > 2: The usage data is more than 1 days. The data should be the start, end and 0am
* data of every day between the start and end, such as data of 2022-01-01 06:00,
* 2022-01-02 00:00, 2022-01-03 00:00 and 2022-01-03 08:00.
* data of every day between the start and end, such as data of 2022-01-01 06:00, 2022-01-02
* 00:00, 2022-01-03 00:00 and 2022-01-03 08:00.
*/
private final PeriodBatteryLevelData mDailyBatteryLevels;
// The size of hourly data must be the size of daily data - 1.
private final List<PeriodBatteryLevelData> mHourlyBatteryLevelsPerDay;
@@ -118,8 +123,9 @@ public final class BatteryLevelData {
final int hourlyHighlightIndex =
(dailyHighlightIndex == BatteryChartViewModel.SELECTED_INDEX_INVALID)
? BatteryChartViewModel.SELECTED_INDEX_INVALID
: mHourlyBatteryLevelsPerDay.get(dailyHighlightIndex)
.getIndexByTimestamps(startTimestamp, endTimestamp);
: mHourlyBatteryLevelsPerDay
.get(dailyHighlightIndex)
.getIndexByTimestamps(startTimestamp, endTimestamp);
return Pair.create(dailyHighlightIndex, hourlyHighlightIndex);
}
@@ -133,14 +139,16 @@ public final class BatteryLevelData {
@Override
public String toString() {
return String.format(Locale.ENGLISH,
return String.format(
Locale.ENGLISH,
"dailyBatteryLevels: %s; hourlyBatteryLevelsPerDay: %s",
Objects.toString(mDailyBatteryLevels),
Objects.toString(mHourlyBatteryLevelsPerDay));
}
@Nullable
static BatteryLevelData combine(@Nullable BatteryLevelData existingBatteryLevelData,
static BatteryLevelData combine(
@Nullable BatteryLevelData existingBatteryLevelData,
List<BatteryEvent> batteryLevelRecordEvents) {
final Map<Long, Integer> batteryLevelMap = new ArrayMap<>(batteryLevelRecordEvents.size());
for (BatteryEvent event : batteryLevelRecordEvents) {
@@ -152,7 +160,8 @@ public final class BatteryLevelData {
for (int dayIndex = 0; dayIndex < multiDaysData.size(); dayIndex++) {
PeriodBatteryLevelData oneDayData = multiDaysData.get(dayIndex);
for (int hourIndex = 0; hourIndex < oneDayData.getLevels().size(); hourIndex++) {
batteryLevelMap.put(oneDayData.getTimestamps().get(hourIndex),
batteryLevelMap.put(
oneDayData.getTimestamps().get(hourIndex),
oneDayData.getLevels().get(hourIndex));
}
}
@@ -163,11 +172,10 @@ public final class BatteryLevelData {
/**
* Computes expected daily timestamp slots.
*
* The valid result should be composed of 3 parts:
* 1) start timestamp
* 2) every 00:00 timestamp (default timezone) between the start and end
* 3) end timestamp
* Otherwise, returns an empty list.
* <p>The valid result should be composed of 3 parts: <br>
* 1) start timestamp <br>
* 2) every 00:00 timestamp (default timezone) between the start and end <br>
* 3) end timestamp Otherwise, returns an empty list.
*/
@VisibleForTesting
static List<Long> getDailyTimestamps(final List<Long> timestampList) {
@@ -176,7 +184,8 @@ public final class BatteryLevelData {
final List<Long> dailyTimestampList = new ArrayList<>();
final long startTimestamp = timestampList.get(0);
final long endTimestamp = timestampList.get(timestampList.size() - 1);
for (long timestamp = startTimestamp; timestamp < endTimestamp;
for (long timestamp = startTimestamp;
timestamp < endTimestamp;
timestamp = TimestampUtils.getNextDayTimestamp(timestamp)) {
dailyTimestampList.add(timestamp);
}
@@ -193,7 +202,8 @@ public final class BatteryLevelData {
hourlyTimestampsPerDay.add(startTime);
for (long timestamp = TimestampUtils.getNextEvenHourTimestamp(startTime);
timestamp < endTime; timestamp += TIME_SLOT) {
timestamp < endTime;
timestamp += TIME_SLOT) {
hourlyTimestampsPerDay.add(timestamp);
}
hourlyTimestampsPerDay.add(endTime);
@@ -203,4 +213,3 @@ public final class BatteryLevelData {
return hourlyTimestamps;
}
}

View File

@@ -34,9 +34,7 @@ import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.google.android.material.button.MaterialButton;
/**
* A preference for displaying the battery tips card view.
*/
/** A preference for displaying the battery tips card view. */
public class BatteryTipsCardPreference extends Preference implements View.OnClickListener {
private static final String TAG = "BatteryTipsCardPreference";
@@ -55,10 +53,8 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
private int mIconResourceId = 0;
private int mMainButtonStrokeColorResourceId = 0;
@VisibleForTesting
CharSequence mMainButtonLabel;
@VisibleForTesting
CharSequence mDismissButtonLabel;
@VisibleForTesting CharSequence mMainButtonLabel;
@VisibleForTesting CharSequence mDismissButtonLabel;
public BatteryTipsCardPreference(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -76,9 +72,7 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
mOnRejectListener = listener;
}
/**
* Sets the icon in tips card.
*/
/** Sets the icon in tips card. */
public void setIconResourceId(int resourceId) {
if (mIconResourceId != resourceId) {
mIconResourceId = resourceId;
@@ -86,9 +80,7 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
}
}
/**
* Sets the stroke color of main button in tips card.
*/
/** Sets the stroke color of main button in tips card. */
public void setMainButtonStrokeColorResourceId(int resourceId) {
if (mMainButtonStrokeColorResourceId != resourceId) {
mMainButtonStrokeColorResourceId = resourceId;
@@ -96,9 +88,7 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
}
}
/**
* Sets the label of main button in tips card.
*/
/** Sets the label of main button in tips card. */
public void setMainButtonLabel(CharSequence label) {
if (!TextUtils.equals(mMainButtonLabel, label)) {
mMainButtonLabel = label;
@@ -106,9 +96,7 @@ public class BatteryTipsCardPreference extends Preference implements View.OnClic
}
}
/**
* Sets the label of dismiss button in tips card.
*/
/** Sets the label of dismiss button in tips card. */
public void setDismissButtonLabel(CharSequence label) {
if (!TextUtils.equals(mDismissButtonLabel, label)) {
mDismissButtonLabel = label;

View File

@@ -51,12 +51,9 @@ public class BatteryTipsController extends BasePreferenceController {
private OnAnomalyConfirmListener mOnAnomalyConfirmListener;
private OnAnomalyRejectListener mOnAnomalyRejectListener;
@VisibleForTesting
BatteryTipsCardPreference mCardPreference;
@VisibleForTesting
AnomalyEventWrapper mAnomalyEventWrapper = null;
@VisibleForTesting
Boolean mIsAcceptable = false;
@VisibleForTesting BatteryTipsCardPreference mCardPreference;
@VisibleForTesting AnomalyEventWrapper mAnomalyEventWrapper = null;
@VisibleForTesting Boolean mIsAcceptable = false;
public BatteryTipsController(Context context) {
super(context, ROOT_PREFERENCE_KEY);
@@ -94,7 +91,8 @@ public class BatteryTipsController extends BasePreferenceController {
}
mCardPreference.setVisible(false);
mMetricsFeatureProvider.action(
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT,
mContext,
SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT,
mAnomalyEventWrapper.getEventId());
}
@@ -117,28 +115,31 @@ public class BatteryTipsController extends BasePreferenceController {
}
// Set battery tips card listener
mCardPreference.setOnConfirmListener(() -> {
mCardPreference.setVisible(false);
if (mOnAnomalyConfirmListener != null) {
mOnAnomalyConfirmListener.onAnomalyConfirm();
} else if (mAnomalyEventWrapper.launchSubSetting()) {
mMetricsFeatureProvider.action(
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, eventId);
}
});
mCardPreference.setOnRejectListener(() -> {
mCardPreference.setVisible(false);
if (mOnAnomalyRejectListener != null) {
mOnAnomalyRejectListener.onAnomalyReject();
}
// For anomaly events with same record key, dismissed until next time full charged.
final String dismissRecordKey = mAnomalyEventWrapper.getDismissRecordKey();
if (!TextUtils.isEmpty(dismissRecordKey)) {
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, dismissRecordKey);
}
mMetricsFeatureProvider.action(
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, eventId);
});
mCardPreference.setOnConfirmListener(
() -> {
mCardPreference.setVisible(false);
if (mOnAnomalyConfirmListener != null) {
mOnAnomalyConfirmListener.onAnomalyConfirm();
} else if (mAnomalyEventWrapper.launchSubSetting()) {
mMetricsFeatureProvider.action(
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_ACCEPT, eventId);
}
});
mCardPreference.setOnRejectListener(
() -> {
mCardPreference.setVisible(false);
if (mOnAnomalyRejectListener != null) {
mOnAnomalyRejectListener.onAnomalyReject();
}
// For anomaly events with same record key, dismissed until next time full
// charged.
final String dismissRecordKey = mAnomalyEventWrapper.getDismissRecordKey();
if (!TextUtils.isEmpty(dismissRecordKey)) {
DatabaseUtils.setDismissedPowerAnomalyKeys(mContext, dismissRecordKey);
}
mMetricsFeatureProvider.action(
mContext, SettingsEnums.ACTION_BATTERY_TIPS_CARD_DISMISS, eventId);
});
mCardPreference.setVisible(true);
mMetricsFeatureProvider.action(

View File

@@ -58,7 +58,7 @@ import java.util.Set;
/** Controller for battery usage breakdown preference group. */
public class BatteryUsageBreakdownController extends BasePreferenceController
implements LifecycleObserver, OnResume, OnDestroy {
implements LifecycleObserver, OnResume, OnDestroy {
private static final String TAG = "BatteryUsageBreakdownController";
private static final String ROOT_PREFERENCE_KEY = "battery_usage_breakdown";
private static final String FOOTER_PREFERENCE_KEY = "battery_usage_footer";
@@ -74,45 +74,33 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
private final MetricsFeatureProvider mMetricsFeatureProvider;
private final Handler mHandler = new Handler(Looper.getMainLooper());
@VisibleForTesting
final Map<String, Preference> mPreferenceCache = new ArrayMap<>();
@VisibleForTesting final Map<String, Preference> mPreferenceCache = new ArrayMap<>();
private int mSpinnerPosition;
private String mSlotTimestamp;
@VisibleForTesting
Context mPrefContext;
@VisibleForTesting
PreferenceCategory mRootPreference;
@VisibleForTesting
SpinnerPreference mSpinnerPreference;
@VisibleForTesting
PreferenceGroup mAppListPreferenceGroup;
@VisibleForTesting
FooterPreference mFooterPreference;
@VisibleForTesting
BatteryDiffData mBatteryDiffData;
@VisibleForTesting
String mPercentLessThanThresholdText;
@VisibleForTesting
boolean mIsHighlightSlot;
@VisibleForTesting
String mAnomalyEventId;
@VisibleForTesting
String mAnomalyEntryKey;
@VisibleForTesting
String mAnomalyHintString;
@VisibleForTesting
String mAnomalyHintPrefKey;
@VisibleForTesting Context mPrefContext;
@VisibleForTesting PreferenceCategory mRootPreference;
@VisibleForTesting SpinnerPreference mSpinnerPreference;
@VisibleForTesting PreferenceGroup mAppListPreferenceGroup;
@VisibleForTesting FooterPreference mFooterPreference;
@VisibleForTesting BatteryDiffData mBatteryDiffData;
@VisibleForTesting String mPercentLessThanThresholdText;
@VisibleForTesting boolean mIsHighlightSlot;
@VisibleForTesting String mAnomalyEventId;
@VisibleForTesting String mAnomalyEntryKey;
@VisibleForTesting String mAnomalyHintString;
@VisibleForTesting String mAnomalyHintPrefKey;
public BatteryUsageBreakdownController(
Context context, Lifecycle lifecycle, SettingsActivity activity,
Context context,
Lifecycle lifecycle,
SettingsActivity activity,
InstrumentedPreferenceFragment fragment) {
super(context, ROOT_PREFERENCE_KEY);
mActivity = activity;
mFragment = fragment;
mMetricsFeatureProvider =
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
if (lifecycle != null) {
lifecycle.addObserver(this);
}
@@ -133,7 +121,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
@Override
public void onDestroy() {
mHandler.removeCallbacksAndMessages(/*token=*/ null);
mHandler.removeCallbacksAndMessages(/* token= */ null);
mPreferenceCache.clear();
mAppListPreferenceGroup.removeAll();
}
@@ -149,14 +137,17 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
}
private boolean isAnomalyBatteryDiffEntry(BatteryDiffEntry entry) {
return mIsHighlightSlot && mAnomalyEntryKey != null
return mIsHighlightSlot
&& mAnomalyEntryKey != null
&& mAnomalyEntryKey.equals(entry.getKey());
}
private String getActionKey(BatteryDiffEntry entry) {
final String actionKey = TextUtils.isEmpty(entry.getPackageName())
? PACKAGE_NAME_NONE : entry.getPackageName();
return !isAnomalyBatteryDiffEntry(entry) ? actionKey : actionKey + "|" + mAnomalyEventId;
final String actionKey =
TextUtils.isEmpty(entry.getPackageName())
? PACKAGE_NAME_NONE
: entry.getPackageName();
return !isAnomalyBatteryDiffEntry(entry) ? actionKey : actionKey + "|" + mAnomalyEventId;
}
@Override
@@ -174,15 +165,24 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
/* pageId */ SettingsEnums.OPEN_BATTERY_USAGE,
getActionKey(diffEntry),
(int) Math.round(diffEntry.getPercentage()));
Log.d(TAG, String.format("handleClick() label=%s key=%s package=%s",
diffEntry.getAppLabel(), diffEntry.getKey(), diffEntry.getPackageName()));
final String anomalyHintPrefKey = isAnomalyBatteryDiffEntry(diffEntry)
? mAnomalyHintPrefKey : null;
final String anomalyHintText = isAnomalyBatteryDiffEntry(diffEntry)
? mAnomalyHintString : null;
AdvancedPowerUsageDetail.startBatteryDetailPage(mActivity, mFragment.getMetricsCategory(),
diffEntry, powerPref.getPercentage(), mSlotTimestamp,
/*showTimeInformation=*/ true, anomalyHintPrefKey, anomalyHintText);
Log.d(
TAG,
String.format(
"handleClick() label=%s key=%s package=%s",
diffEntry.getAppLabel(), diffEntry.getKey(), diffEntry.getPackageName()));
final String anomalyHintPrefKey =
isAnomalyBatteryDiffEntry(diffEntry) ? mAnomalyHintPrefKey : null;
final String anomalyHintText =
isAnomalyBatteryDiffEntry(diffEntry) ? mAnomalyHintString : null;
AdvancedPowerUsageDetail.startBatteryDetailPage(
mActivity,
mFragment.getMetricsCategory(),
diffEntry,
powerPref.getPercentage(),
mSlotTimestamp,
/* showTimeInformation= */ true,
anomalyHintPrefKey,
anomalyHintText);
return true;
}
@@ -194,15 +194,16 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
mSpinnerPreference = screen.findPreference(SPINNER_PREFERENCE_KEY);
mAppListPreferenceGroup = screen.findPreference(APP_LIST_PREFERENCE_KEY);
mFooterPreference = screen.findPreference(FOOTER_PREFERENCE_KEY);
mPercentLessThanThresholdText = mPrefContext.getString(
R.string.battery_usage_less_than_percent,
Utils.formatPercentage(BatteryDiffData.SMALL_PERCENTAGE_THRESHOLD, false));
mPercentLessThanThresholdText =
mPrefContext.getString(
R.string.battery_usage_less_than_percent,
Utils.formatPercentage(BatteryDiffData.SMALL_PERCENTAGE_THRESHOLD, false));
mAppListPreferenceGroup.setOrderingAsAdded(false);
mSpinnerPreference.initializeSpinner(
new String[]{
mPrefContext.getString(R.string.battery_usage_spinner_view_by_apps),
mPrefContext.getString(R.string.battery_usage_spinner_view_by_systems)
new String[] {
mPrefContext.getString(R.string.battery_usage_spinner_view_by_apps),
mPrefContext.getString(R.string.battery_usage_spinner_view_by_systems)
},
new AdapterView.OnItemSelectedListener() {
@Override
@@ -210,35 +211,38 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
AdapterView<?> parent, View view, int position, long id) {
if (mSpinnerPosition != position) {
mSpinnerPosition = position;
mHandler.post(() -> {
removeAndCacheAllUnusedPreferences();
addAllPreferences();
mMetricsFeatureProvider.action(
mPrefContext,
SettingsEnums.ACTION_BATTERY_USAGE_SPINNER,
mSpinnerPosition);
});
mHandler.post(
() -> {
removeAndCacheAllUnusedPreferences();
addAllPreferences();
mMetricsFeatureProvider.action(
mPrefContext,
SettingsEnums.ACTION_BATTERY_USAGE_SPINNER,
mSpinnerPosition);
});
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
public void onNothingSelected(AdapterView<?> parent) {}
});
}
/**
* Updates UI when the battery usage is updated.
* @param slotUsageData The battery usage diff data for the selected slot. This is used in
* the app list.
*
* @param slotUsageData The battery usage diff data for the selected slot. This is used in the
* app list.
* @param slotTimestamp The selected slot timestamp information. This is used in the battery
* usage breakdown category.
* @param isAllUsageDataEmpty Whether all the battery usage data is null or empty. This is
* used when showing the footer.
* usage breakdown category.
* @param isAllUsageDataEmpty Whether all the battery usage data is null or empty. This is used
* when showing the footer.
*/
void handleBatteryUsageUpdated(
BatteryDiffData slotUsageData, String slotTimestamp,
boolean isAllUsageDataEmpty, boolean isHighlightSlot,
BatteryDiffData slotUsageData,
String slotTimestamp,
boolean isAllUsageDataEmpty,
boolean isHighlightSlot,
Optional<AnomalyEventWrapper> optionalAnomalyEventWrapper) {
mBatteryDiffData = slotUsageData;
mSlotTimestamp = slotTimestamp;
@@ -247,14 +251,15 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
if (optionalAnomalyEventWrapper != null) {
final AnomalyEventWrapper anomalyEventWrapper =
optionalAnomalyEventWrapper.orElse(null);
mAnomalyEventId = anomalyEventWrapper != null
? anomalyEventWrapper.getEventId() : null;
mAnomalyEntryKey = anomalyEventWrapper != null
? anomalyEventWrapper.getAnomalyEntryKey() : null;
mAnomalyHintString = anomalyEventWrapper != null
? anomalyEventWrapper.getAnomalyHintString() : null;
mAnomalyHintPrefKey = anomalyEventWrapper != null
? anomalyEventWrapper.getAnomalyHintPrefKey() : null;
mAnomalyEventId = anomalyEventWrapper != null ? anomalyEventWrapper.getEventId() : null;
mAnomalyEntryKey =
anomalyEventWrapper != null ? anomalyEventWrapper.getAnomalyEntryKey() : null;
mAnomalyHintString =
anomalyEventWrapper != null ? anomalyEventWrapper.getAnomalyHintString() : null;
mAnomalyHintPrefKey =
anomalyEventWrapper != null
? anomalyEventWrapper.getAnomalyHintPrefKey()
: null;
}
showCategoryTitle(slotTimestamp);
@@ -263,35 +268,39 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
}
private void showCategoryTitle(String slotTimestamp) {
mRootPreference.setTitle(slotTimestamp == null
? mPrefContext.getString(
R.string.battery_usage_breakdown_title_since_last_full_charge)
: mPrefContext.getString(
R.string.battery_usage_breakdown_title_for_slot, slotTimestamp));
mRootPreference.setTitle(
slotTimestamp == null
? mPrefContext.getString(
R.string.battery_usage_breakdown_title_since_last_full_charge)
: mPrefContext.getString(
R.string.battery_usage_breakdown_title_for_slot, slotTimestamp));
mRootPreference.setVisible(true);
}
private void showFooterPreference(boolean isAllBatteryUsageEmpty) {
mFooterPreference.setTitle(mPrefContext.getString(
isAllBatteryUsageEmpty
? R.string.battery_usage_screen_footer_empty
: R.string.battery_usage_screen_footer));
mFooterPreference.setTitle(
mPrefContext.getString(
isAllBatteryUsageEmpty
? R.string.battery_usage_screen_footer_empty
: R.string.battery_usage_screen_footer));
mFooterPreference.setVisible(true);
}
private void showSpinnerAndAppList() {
if (mBatteryDiffData == null) {
mHandler.post(() -> {
removeAndCacheAllUnusedPreferences();
});
mHandler.post(
() -> {
removeAndCacheAllUnusedPreferences();
});
return;
}
mSpinnerPreference.setVisible(true);
mAppListPreferenceGroup.setVisible(true);
mHandler.post(() -> {
removeAndCacheAllUnusedPreferences();
addAllPreferences();
});
mHandler.post(
() -> {
removeAndCacheAllUnusedPreferences();
addAllPreferences();
});
}
private List<BatteryDiffEntry> getBatteryDiffEntries() {
@@ -348,8 +357,11 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
}
prefIndex++;
}
Log.d(TAG, String.format("addAllPreferences() is finished in %d/ms",
(System.currentTimeMillis() - start)));
Log.d(
TAG,
String.format(
"addAllPreferences() is finished in %d/ms",
(System.currentTimeMillis() - start)));
}
@VisibleForTesting
@@ -372,8 +384,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
}
@VisibleForTesting
void setPreferencePercentage(
PowerGaugePreference preference, BatteryDiffEntry entry) {
void setPreferencePercentage(PowerGaugePreference preference, BatteryDiffEntry entry) {
preference.setPercentage(
entry.getPercentage() < BatteryDiffData.SMALL_PERCENTAGE_THRESHOLD
? mPercentLessThanThresholdText
@@ -383,11 +394,13 @@ public class BatteryUsageBreakdownController extends BasePreferenceController
}
@VisibleForTesting
void setPreferenceSummary(
PowerGaugePreference preference, BatteryDiffEntry entry) {
void setPreferenceSummary(PowerGaugePreference preference, BatteryDiffEntry entry) {
preference.setSummary(
BatteryUtils.buildBatteryUsageTimeSummary(mPrefContext, entry.isSystemEntry(),
entry.mForegroundUsageTimeInMs, entry.mBackgroundUsageTimeInMs,
BatteryUtils.buildBatteryUsageTimeSummary(
mPrefContext,
entry.isSystemEntry(),
entry.mForegroundUsageTimeInMs,
entry.mBackgroundUsageTimeInMs,
entry.mScreenOnTimeInMs));
}
}

View File

@@ -36,23 +36,23 @@ import java.util.concurrent.Executors;
/** A {@link BatteryUsageBroadcastReceiver} for battery usage data requesting. */
public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "BatteryUsageBroadcastReceiver";
/** An intent action to request Settings to clear cache data. */
public static final String ACTION_CLEAR_BATTERY_CACHE_DATA =
"com.android.settings.battery.action.CLEAR_BATTERY_CACHE_DATA";
/** An intent action for power is plugging. */
public static final String ACTION_BATTERY_PLUGGING =
"com.android.settings.battery.action.ACTION_BATTERY_PLUGGING";
/** An intent action for power is unplugging. */
public static final String ACTION_BATTERY_UNPLUGGING =
"com.android.settings.battery.action.ACTION_BATTERY_UNPLUGGING";
@VisibleForTesting
static long sBroadcastDelayFromBoot = Duration.ofMinutes(40).toMillis();
@VisibleForTesting
static boolean sIsDebugMode = Build.TYPE.equals("userdebug");
@VisibleForTesting static long sBroadcastDelayFromBoot = Duration.ofMinutes(40).toMillis();
@VisibleForTesting static boolean sIsDebugMode = Build.TYPE.equals("userdebug");
@VisibleForTesting
boolean mFetchBatteryUsageData = false;
@VisibleForTesting boolean mFetchBatteryUsageData = false;
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
@@ -68,9 +68,10 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver {
return;
}
DatabaseUtils.recordDateTime(context, action);
final String fullChargeIntentAction = FeatureFactory.getFeatureFactory()
.getPowerUsageFeatureProvider()
.getFullChargeIntentAction();
final String fullChargeIntentAction =
FeatureFactory.getFeatureFactory()
.getPowerUsageFeatureProvider()
.getFullChargeIntentAction();
switch (action) {
case Intent.ACTION_BATTERY_LEVEL_CHANGED:
// Only when fullChargeIntentAction is ACTION_BATTERY_LEVEL_CHANGED,
@@ -117,13 +118,16 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver {
final long broadcastDelay = sBroadcastDelayFromBoot - SystemClock.elapsedRealtime();
// If current boot time is smaller than expected delay, cancel sending the broadcast.
if (delayHourlyJobWhenBooting && broadcastDelay > 0) {
Log.d(TAG, "cancel sendBroadcastToFetchUsageData when broadcastDelay is "
+ broadcastDelay + "ms.");
Log.d(
TAG,
"cancel sendBroadcastToFetchUsageData when broadcastDelay is "
+ broadcastDelay
+ "ms.");
return;
}
mFetchBatteryUsageData = true;
BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ true);
BatteryUsageDataLoader.enqueueWork(context, /* isFullChargeStart= */ true);
BootBroadcastReceiver.invokeJobRecheck(context);
}
@@ -131,7 +135,11 @@ public final class BatteryUsageBroadcastReceiver extends BroadcastReceiver {
final long timestamp = System.currentTimeMillis();
final Intent intent = BatteryUtils.getBatteryIntent(context);
final int batteryLevel = BatteryStatus.getBatteryLevel(intent);
mExecutor.execute(() -> DatabaseUtils.sendBatteryEventData(context,
ConvertUtils.convertToBatteryEvent(timestamp, batteryEventType, batteryLevel)));
mExecutor.execute(
() ->
DatabaseUtils.sendBatteryEventData(
context,
ConvertUtils.convertToBatteryEvent(
timestamp, batteryEventType, batteryLevel)));
}
}

View File

@@ -53,6 +53,7 @@ public class BatteryUsageContentProvider extends ContentProvider {
/** Codes */
private static final int BATTERY_STATE_CODE = 1;
private static final int APP_USAGE_LATEST_TIMESTAMP_CODE = 2;
private static final int APP_USAGE_EVENT_CODE = 3;
private static final int BATTERY_EVENT_CODE = 4;
@@ -67,32 +68,32 @@ public class BatteryUsageContentProvider extends ContentProvider {
static {
sUriMatcher.addURI(
DatabaseUtils.AUTHORITY,
/*path=*/ DatabaseUtils.BATTERY_STATE_TABLE,
/*code=*/ BATTERY_STATE_CODE);
/* path= */ DatabaseUtils.BATTERY_STATE_TABLE,
/* code= */ BATTERY_STATE_CODE);
sUriMatcher.addURI(
DatabaseUtils.AUTHORITY,
/*path=*/ DatabaseUtils.APP_USAGE_LATEST_TIMESTAMP_PATH,
/*code=*/ APP_USAGE_LATEST_TIMESTAMP_CODE);
/* path= */ DatabaseUtils.APP_USAGE_LATEST_TIMESTAMP_PATH,
/* code= */ APP_USAGE_LATEST_TIMESTAMP_CODE);
sUriMatcher.addURI(
DatabaseUtils.AUTHORITY,
/*path=*/ DatabaseUtils.APP_USAGE_EVENT_TABLE,
/*code=*/ APP_USAGE_EVENT_CODE);
/* path= */ DatabaseUtils.APP_USAGE_EVENT_TABLE,
/* code= */ APP_USAGE_EVENT_CODE);
sUriMatcher.addURI(
DatabaseUtils.AUTHORITY,
/*path=*/ DatabaseUtils.BATTERY_EVENT_TABLE,
/*code=*/ BATTERY_EVENT_CODE);
/* path= */ DatabaseUtils.BATTERY_EVENT_TABLE,
/* code= */ BATTERY_EVENT_CODE);
sUriMatcher.addURI(
DatabaseUtils.AUTHORITY,
/*path=*/ DatabaseUtils.LAST_FULL_CHARGE_TIMESTAMP_PATH,
/*code=*/ LAST_FULL_CHARGE_TIMESTAMP_CODE);
/* path= */ DatabaseUtils.LAST_FULL_CHARGE_TIMESTAMP_PATH,
/* code= */ LAST_FULL_CHARGE_TIMESTAMP_CODE);
sUriMatcher.addURI(
DatabaseUtils.AUTHORITY,
/*path=*/ DatabaseUtils.BATTERY_STATE_LATEST_TIMESTAMP_PATH,
/*code=*/ BATTERY_STATE_LATEST_TIMESTAMP_CODE);
/* path= */ DatabaseUtils.BATTERY_STATE_LATEST_TIMESTAMP_PATH,
/* code= */ BATTERY_STATE_LATEST_TIMESTAMP_CODE);
sUriMatcher.addURI(
DatabaseUtils.AUTHORITY,
/*path=*/ DatabaseUtils.BATTERY_USAGE_SLOT_TABLE,
/*code=*/ BATTERY_USAGE_SLOT_CODE);
/* path= */ DatabaseUtils.BATTERY_USAGE_SLOT_TABLE,
/* code= */ BATTERY_USAGE_SLOT_CODE);
}
private Clock mClock;
@@ -177,7 +178,7 @@ public class BatteryUsageContentProvider extends ContentProvider {
throw new IllegalArgumentException("unknown URI: " + uri);
}
} catch (RuntimeException e) {
if (e instanceof IllegalArgumentException) {
if (e instanceof IllegalArgumentException) {
throw e;
}
Log.e(TAG, "insert() from:" + uri + " error:", e);
@@ -208,8 +209,10 @@ public class BatteryUsageContentProvider extends ContentProvider {
} catch (RuntimeException e) {
Log.e(TAG, "query() from:" + uri + " error:", e);
}
Log.d(TAG, String.format("getLastFullChargeTimestamp() in %d/ms",
mClock.millis() - timestamp));
Log.d(
TAG,
String.format(
"getLastFullChargeTimestamp() in %d/ms", mClock.millis() - timestamp));
return cursor;
}
@@ -222,8 +225,11 @@ public class BatteryUsageContentProvider extends ContentProvider {
} catch (RuntimeException e) {
Log.e(TAG, "query() from:" + uri + " error:", e);
}
Log.d(TAG, String.format("getBatteryStateLatestTimestamp() no later than %d in %d/ms",
queryTimestamp, mClock.millis() - timestamp));
Log.d(
TAG,
String.format(
"getBatteryStateLatestTimestamp() no later than %d in %d/ms",
queryTimestamp, mClock.millis() - timestamp));
return cursor;
}
@@ -236,8 +242,11 @@ public class BatteryUsageContentProvider extends ContentProvider {
} catch (RuntimeException e) {
Log.e(TAG, "query() from:" + uri + " error:", e);
}
Log.d(TAG, String.format("getBatteryStates() after %d in %d/ms",
queryTimestamp, mClock.millis() - timestamp));
Log.d(
TAG,
String.format(
"getBatteryStates() after %d in %d/ms",
queryTimestamp, mClock.millis() - timestamp));
return cursor;
}
@@ -270,8 +279,11 @@ public class BatteryUsageContentProvider extends ContentProvider {
} catch (RuntimeException e) {
Log.e(TAG, "query() from:" + uri + " error:", e);
}
Log.d(TAG, String.format("getAppUsageLatestTimestamp() for user %d in %d/ms",
queryUserId, (mClock.millis() - timestamp)));
Log.d(
TAG,
String.format(
"getAppUsageLatestTimestamp() for user %d in %d/ms",
queryUserId, (mClock.millis() - timestamp)));
return cursor;
}

Some files were not shown because too many files have changed in this diff Show More