blob: ed06cce59d12c6761e0294012f4991a31d969f51 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.fuelgauge.batterytip;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.app.StatsManager;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import android.os.UserManager;
import androidx.annotation.NonNull;
import com.android.internal.util.CollectionUtils;
import com.android.settings.SettingsActivity;
import com.android.settings.core.InstrumentedPreferenceFragment;
import com.android.settings.fuelgauge.batterytip.actions.BatterySaverAction;
import com.android.settings.fuelgauge.batterytip.actions.BatteryTipAction;
import com.android.settings.fuelgauge.batterytip.actions.OpenBatterySaverAction;
import com.android.settings.fuelgauge.batterytip.actions.OpenRestrictAppFragmentAction;
import com.android.settings.fuelgauge.batterytip.actions.RestrictAppAction;
import com.android.settings.fuelgauge.batterytip.actions.SmartBatteryAction;
import com.android.settings.fuelgauge.batterytip.actions.UnrestrictAppAction;
import com.android.settings.fuelgauge.batterytip.tips.AppLabelPredicate;
import com.android.settings.fuelgauge.batterytip.tips.AppRestrictionPredicate;
import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip;
import java.util.ArrayList;
import java.util.List;
/**
* Utility class for {@link BatteryTip}
*/
public class BatteryTipUtils {
private static final int REQUEST_CODE = 0;
/**
* Get a list of restricted apps with {@link AppOpsManager#OP_RUN_ANY_IN_BACKGROUND}
*/
@NonNull
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<AppInfo> appInfos = new ArrayList<>();
for (int i = 0, size = CollectionUtils.size(packageOpsList); i < size; i++) {
final AppOpsManager.PackageOps packageOps = packageOpsList.get(i);
final List<AppOpsManager.OpEntry> entries = packageOps.getOps();
for (int j = 0, entriesSize = entries.size(); j < entriesSize; j++) {
AppOpsManager.OpEntry entry = entries.get(j);
if (entry.getOp() != AppOpsManager.OP_RUN_ANY_IN_BACKGROUND) {
continue;
}
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());
}
}
}
return appInfos;
}
/**
* Get a corresponding action based on {@code batteryTip}
* @param batteryTip used to detect which action to choose
* @param settingsActivity used to populate {@link BatteryTipAction}
* @param fragment used to populate {@link BatteryTipAction}
* @return an action for {@code batteryTip}
*/
public static BatteryTipAction getActionForBatteryTip(BatteryTip batteryTip,
SettingsActivity settingsActivity, InstrumentedPreferenceFragment fragment) {
switch (batteryTip.getType()) {
case BatteryTip.TipType.SMART_BATTERY_MANAGER:
return new SmartBatteryAction(settingsActivity, fragment);
case BatteryTip.TipType.BATTERY_SAVER:
case BatteryTip.TipType.LOW_BATTERY:
if (batteryTip.getState() == BatteryTip.StateType.HANDLED) {
return new OpenBatterySaverAction(settingsActivity);
} else {
return new BatterySaverAction(settingsActivity);
}
case BatteryTip.TipType.APP_RESTRICTION:
if (batteryTip.getState() == BatteryTip.StateType.HANDLED) {
return new OpenRestrictAppFragmentAction(fragment, (RestrictAppTip) batteryTip);
} else {
return new RestrictAppAction(settingsActivity, (RestrictAppTip) batteryTip);
}
case BatteryTip.TipType.REMOVE_APP_RESTRICTION:
return new UnrestrictAppAction(settingsActivity, (UnrestrictAppTip) batteryTip);
default:
return null;
}
}
/**
* 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);
statsManager.setBroadcastSubscriber(pendingIntent,
StatsManagerConfig.ANOMALY_CONFIG_KEY, StatsManagerConfig.SUBSCRIBER_ID);
}
/**
* 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);
// Remove it if it doesn't have label or been restricted
highUsageApps.removeIf(AppLabelPredicate.getInstance(context)
.or(AppRestrictionPredicate.getInstance(context)));
return highUsageApps;
}
}