1 /*
2  * Copyright (C) 2019 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 android.os;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.annotation.RequiresPermission;
22 import android.annotation.SystemApi;
23 import android.annotation.SystemService;
24 import android.annotation.TestApi;
25 import android.content.Context;
26 
27 import java.lang.annotation.Retention;
28 import java.lang.annotation.RetentionPolicy;
29 import java.util.Collections;
30 import java.util.List;
31 
32 /**
33  * Interface to access and modify the power save whitelist.
34  *
35  * @hide
36  */
37 @SystemApi
38 @TestApi
39 @SystemService(Context.POWER_WHITELIST_MANAGER)
40 public class PowerWhitelistManager {
41     private final Context mContext;
42     // Proxy to DeviceIdleController for now
43     // TODO: migrate to PowerWhitelistController
44     private final IDeviceIdleController mService;
45 
46     /**
47      * Indicates that an unforeseen event has occurred and the app should be whitelisted to handle
48      * it.
49      */
50     public static final int EVENT_UNSPECIFIED = 0;
51 
52     /**
53      * Indicates that an SMS event has occurred and the app should be whitelisted to handle it.
54      */
55     public static final int EVENT_SMS = 1;
56 
57     /**
58      * Indicates that an MMS event has occurred and the app should be whitelisted to handle it.
59      */
60     public static final int EVENT_MMS = 2;
61 
62     /**
63      * @hide
64      */
65     @Retention(RetentionPolicy.SOURCE)
66     @IntDef(prefix = {"EVENT_"}, value = {
67             EVENT_UNSPECIFIED,
68             EVENT_SMS,
69             EVENT_MMS,
70     })
71     public @interface WhitelistEvent {
72     }
73 
74     /**
75      * @hide
76      */
PowerWhitelistManager(@onNull Context context)77     public PowerWhitelistManager(@NonNull Context context) {
78         mContext = context;
79         mService = context.getSystemService(DeviceIdleManager.class).getService();
80     }
81 
82     /**
83      * Add the specified package to the permanent power save whitelist.
84      */
85     @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
addToWhitelist(@onNull String packageName)86     public void addToWhitelist(@NonNull String packageName) {
87         addToWhitelist(Collections.singletonList(packageName));
88     }
89 
90     /**
91      * Add the specified packages to the permanent power save whitelist.
92      */
93     @RequiresPermission(android.Manifest.permission.DEVICE_POWER)
addToWhitelist(@onNull List<String> packageNames)94     public void addToWhitelist(@NonNull List<String> packageNames) {
95         try {
96             mService.addPowerSaveWhitelistApps(packageNames);
97         } catch (RemoteException e) {
98             throw e.rethrowFromSystemServer();
99         }
100     }
101 
102     /**
103      * Get a list of app IDs of app that are whitelisted. This does not include temporarily
104      * whitelisted apps.
105      *
106      * @param includingIdle Set to true if the app should be whitelisted from device idle as well
107      *                      as other power save restrictions
108      * @hide
109      */
110     @NonNull
getWhitelistedAppIds(boolean includingIdle)111     public int[] getWhitelistedAppIds(boolean includingIdle) {
112         try {
113             if (includingIdle) {
114                 return mService.getAppIdWhitelist();
115             } else {
116                 return mService.getAppIdWhitelistExceptIdle();
117             }
118         } catch (RemoteException e) {
119             throw e.rethrowFromSystemServer();
120         }
121     }
122 
123     /**
124      * Returns true if the app is whitelisted from power save restrictions. This does not include
125      * temporarily whitelisted apps.
126      *
127      * @param includingIdle Set to true if the app should be whitelisted from device
128      *                      idle as well as other power save restrictions
129      * @hide
130      */
isWhitelisted(@onNull String packageName, boolean includingIdle)131     public boolean isWhitelisted(@NonNull String packageName, boolean includingIdle) {
132         try {
133             if (includingIdle) {
134                 return mService.isPowerSaveWhitelistApp(packageName);
135             } else {
136                 return mService.isPowerSaveWhitelistExceptIdleApp(packageName);
137             }
138         } catch (RemoteException e) {
139             throw e.rethrowFromSystemServer();
140         }
141     }
142 
143     /**
144      * Add an app to the temporary whitelist for a short amount of time.
145      *
146      * @param packageName The package to add to the temp whitelist
147      * @param durationMs How long to keep the app on the temp whitelist for (in milliseconds)
148      */
149     @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
whitelistAppTemporarily(@onNull String packageName, long durationMs)150     public void whitelistAppTemporarily(@NonNull String packageName, long durationMs) {
151         String reason = "from:" + UserHandle.formatUid(Binder.getCallingUid());
152         try {
153             mService.addPowerSaveTempWhitelistApp(packageName, durationMs, mContext.getUserId(),
154                     reason);
155         } catch (RemoteException e) {
156             throw e.rethrowFromSystemServer();
157         }
158     }
159 
160     /**
161      * Add an app to the temporary whitelist for a short amount of time for a specific reason.
162      *
163      * @param packageName The package to add to the temp whitelist
164      * @param event The reason to add the app to the temp whitelist
165      * @param reason A human-readable reason explaining why the app is temp whitelisted. Only used
166      *               for logging purposes
167      * @return The duration (in milliseconds) that the app is whitelisted for
168      */
169     @RequiresPermission(android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST)
whitelistAppTemporarilyForEvent(@onNull String packageName, @WhitelistEvent int event, @NonNull String reason)170     public long whitelistAppTemporarilyForEvent(@NonNull String packageName,
171             @WhitelistEvent int event, @NonNull String reason) {
172         try {
173             switch (event) {
174                 case EVENT_MMS:
175                     return mService.addPowerSaveTempWhitelistAppForMms(
176                             packageName, mContext.getUserId(), reason);
177                 case EVENT_SMS:
178                     return mService.addPowerSaveTempWhitelistAppForSms(
179                             packageName, mContext.getUserId(), reason);
180                 case EVENT_UNSPECIFIED:
181                 default:
182                     return mService.whitelistAppTemporarily(
183                             packageName, mContext.getUserId(), reason);
184             }
185         } catch (RemoteException e) {
186             throw e.rethrowFromSystemServer();
187         }
188     }
189 }
190