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:
@@ -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) {
|
||||
|
@@ -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";
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -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() {
|
||||
|
@@ -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) {
|
||||
|
@@ -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());
|
||||
}
|
||||
|
||||
|
@@ -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));
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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) {}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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");
|
||||
|
@@ -71,6 +71,7 @@ public class BatterySaverReceiver extends BroadcastReceiver {
|
||||
|
||||
public interface BatterySaverListener {
|
||||
void onPowerSaveModeChanged();
|
||||
|
||||
void onBatteryChanged(boolean pluggedIn);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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));
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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));
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
|
@@ -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() {
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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";
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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) {
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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<>();
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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) {}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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
|
||||
*/
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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 wasn’t created yet or was removed from memory.
|
||||
* The application exceeded the maximum warm start time - the app was already in memory but
|
||||
* the activity wasn’t 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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)
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
@@ -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,
|
||||
|
@@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -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,
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -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) {
|
||||
|
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -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];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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:
|
||||
|
@@ -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;
|
||||
|
@@ -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();
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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,
|
||||
|
@@ -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";
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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(
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
@@ -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
Reference in New Issue
Block a user