• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.fuelgauge.batterytip;
18 
19 import android.app.AppOpsManager;
20 import android.app.PendingIntent;
21 import android.app.StatsManager;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.os.UserHandle;
25 import android.os.UserManager;
26 
27 import androidx.annotation.NonNull;
28 
29 import com.android.internal.util.CollectionUtils;
30 import com.android.settings.SettingsActivity;
31 import com.android.settings.core.InstrumentedPreferenceFragment;
32 import com.android.settings.fuelgauge.batterytip.actions.BatteryDefenderAction;
33 import com.android.settings.fuelgauge.batterytip.actions.BatteryTipAction;
34 import com.android.settings.fuelgauge.batterytip.actions.OpenBatterySaverAction;
35 import com.android.settings.fuelgauge.batterytip.actions.OpenRestrictAppFragmentAction;
36 import com.android.settings.fuelgauge.batterytip.actions.RestrictAppAction;
37 import com.android.settings.fuelgauge.batterytip.actions.SmartBatteryAction;
38 import com.android.settings.fuelgauge.batterytip.actions.UnrestrictAppAction;
39 import com.android.settings.fuelgauge.batterytip.tips.AppLabelPredicate;
40 import com.android.settings.fuelgauge.batterytip.tips.AppRestrictionPredicate;
41 import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
42 import com.android.settings.fuelgauge.batterytip.tips.RestrictAppTip;
43 import com.android.settings.fuelgauge.batterytip.tips.UnrestrictAppTip;
44 
45 import java.util.ArrayList;
46 import java.util.List;
47 
48 /**
49  * Utility class for {@link BatteryTip}
50  */
51 public class BatteryTipUtils {
52     private static final int REQUEST_CODE = 0;
53 
54     /**
55      * Get a list of restricted apps with {@link AppOpsManager#OP_RUN_ANY_IN_BACKGROUND}
56      */
57     @NonNull
getRestrictedAppsList(AppOpsManager appOpsManager, UserManager userManager)58     public static List<AppInfo> getRestrictedAppsList(AppOpsManager appOpsManager,
59             UserManager userManager) {
60         final List<UserHandle> userHandles = userManager.getUserProfiles();
61         final List<AppOpsManager.PackageOps> packageOpsList = appOpsManager.getPackagesForOps(
62                 new int[]{AppOpsManager.OP_RUN_ANY_IN_BACKGROUND});
63         final List<AppInfo> appInfos = new ArrayList<>();
64 
65         for (int i = 0, size = CollectionUtils.size(packageOpsList); i < size; i++) {
66             final AppOpsManager.PackageOps packageOps = packageOpsList.get(i);
67             final List<AppOpsManager.OpEntry> entries = packageOps.getOps();
68             for (int j = 0, entriesSize = entries.size(); j < entriesSize; j++) {
69                 AppOpsManager.OpEntry entry = entries.get(j);
70                 if (entry.getOp() != AppOpsManager.OP_RUN_ANY_IN_BACKGROUND) {
71                     continue;
72                 }
73                 if (entry.getMode() != AppOpsManager.MODE_ALLOWED
74                         && userHandles.contains(
75                         new UserHandle(UserHandle.getUserId(packageOps.getUid())))) {
76                     appInfos.add(new AppInfo.Builder()
77                             .setPackageName(packageOps.getPackageName())
78                             .setUid(packageOps.getUid())
79                             .build());
80                 }
81             }
82         }
83 
84         return appInfos;
85     }
86 
87     /**
88      * Get a corresponding action based on {@code batteryTip}
89      * @param batteryTip used to detect which action to choose
90      * @param settingsActivity used to populate {@link BatteryTipAction}
91      * @param fragment used to populate {@link BatteryTipAction}
92      * @return an action for {@code batteryTip}
93      */
getActionForBatteryTip(BatteryTip batteryTip, SettingsActivity settingsActivity, InstrumentedPreferenceFragment fragment)94     public static BatteryTipAction getActionForBatteryTip(BatteryTip batteryTip,
95             SettingsActivity settingsActivity, InstrumentedPreferenceFragment fragment) {
96         switch (batteryTip.getType()) {
97             case BatteryTip.TipType.SMART_BATTERY_MANAGER:
98                 return new SmartBatteryAction(settingsActivity, fragment);
99             case BatteryTip.TipType.BATTERY_SAVER:
100             case BatteryTip.TipType.LOW_BATTERY:
101                 return new OpenBatterySaverAction(settingsActivity);
102             case BatteryTip.TipType.APP_RESTRICTION:
103                 if (batteryTip.getState() == BatteryTip.StateType.HANDLED) {
104                     return new OpenRestrictAppFragmentAction(fragment, (RestrictAppTip) batteryTip);
105                 } else {
106                     return new RestrictAppAction(settingsActivity, (RestrictAppTip) batteryTip);
107                 }
108             case BatteryTip.TipType.REMOVE_APP_RESTRICTION:
109                 return new UnrestrictAppAction(settingsActivity, (UnrestrictAppTip) batteryTip);
110             case BatteryTip.TipType.BATTERY_DEFENDER:
111                 return new BatteryDefenderAction(settingsActivity);
112             default:
113                 return null;
114         }
115     }
116 
117     /**
118      * Upload the {@link PendingIntent} to {@link StatsManager} for anomaly detection
119      * @throws StatsManager.StatsUnavailableException if failed to communicate with stats service
120      */
uploadAnomalyPendingIntent(Context context, StatsManager statsManager)121     public static void uploadAnomalyPendingIntent(Context context, StatsManager statsManager)
122             throws StatsManager.StatsUnavailableException {
123         final Intent extraIntent = new Intent(context, AnomalyDetectionReceiver.class);
124         final PendingIntent pendingIntent = PendingIntent.getBroadcast(context, REQUEST_CODE,
125                 extraIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
126         statsManager.setBroadcastSubscriber(pendingIntent,
127                 StatsManagerConfig.ANOMALY_CONFIG_KEY, StatsManagerConfig.SUBSCRIBER_ID);
128     }
129 
130     /**
131      * Detect and return anomaly apps after {@code timeAfterMs}
132      */
detectAnomalies(Context context, long timeAfterMs)133     public static List<AppInfo> detectAnomalies(Context context, long timeAfterMs) {
134         final List<AppInfo> highUsageApps = BatteryDatabaseManager.getInstance(context)
135                 .queryAllAnomalies(timeAfterMs, AnomalyDatabaseHelper.State.NEW);
136         // Remove it if it doesn't have label or been restricted
137         highUsageApps.removeIf(AppLabelPredicate.getInstance(context)
138                 .or(AppRestrictionPredicate.getInstance(context)));
139 
140         return highUsageApps;
141     }
142 }
143